chore: remove pageSnapshot option (#34962)

Signed-off-by: Simon Knott <info@simonknott.de>
Co-authored-by: Dmitry Gozman <dgozman@gmail.com>
This commit is contained in:
Simon Knott 2025-02-28 13:16:58 +01:00 committed by GitHub
parent e3eb267ca3
commit 6dcb7d2bf5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 42 additions and 135 deletions

View File

@ -507,27 +507,6 @@ export default defineConfig({
Learn more about [automatic screenshots](../test-use-options.md#recording-options).
## property: TestOptions.pageSnapshot
* since: v1.51
- type: <[PageSnapshotMode]<"off"|"on"|"only-on-failure">>
Whether to automatically capture a ARIA snapshot of the page after each test. Defaults to `'only-on-failure'`.
* `'off'`: Do not capture page snapshots.
* `'on'`: Capture page snapshot after each test.
* `'only-on-failure'`: Capture page snapshot after each test failure.
**Usage**
```js title="playwright.config.ts"
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
pageSnapshot: 'on',
},
});
```
## property: TestOptions.storageState = %%-js-python-context-option-storage-state-%%
* since: v1.10

View File

@ -54,14 +54,18 @@ const PromptButton: React.FC<{
}> = ({ error, result }) => {
const report = useHTMLReport();
const commitInfo = report?.metadata as MetadataWithCommitInfo | undefined;
const pageSnapshot = result?.attachments.find(a => a.name === 'pageSnapshot')?.body;
const prompt = React.useMemo(() => fixTestPrompt(
error,
commitInfo?.gitDiff,
result?.attachments.find(a => a.name === 'pageSnapshot')?.body
), [commitInfo, result, error]);
pageSnapshot
), [commitInfo, pageSnapshot, error]);
const [copied, setCopied] = React.useState(false);
if (!pageSnapshot)
return;
return <button
className='button'
style={{ minWidth: 100 }}

View File

@ -23,7 +23,7 @@ import { setBoxedStackPrefixes, asLocator, createGuid, currentZone, debugMode, i
import { currentTestInfo } from './common/globals';
import { rootTestType } from './common/testType';
import type { Fixtures, PageSnapshotMode, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, VideoMode } from '../types/test';
import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, VideoMode } from '../types/test';
import type { ContextReuseMode } from './common/config';
import type { TestInfoImpl, TestStepInternal } from './worker/testInfo';
import type { ApiCallData, ClientInstrumentation, ClientInstrumentationListener } from '../../playwright-core/src/client/clientInstrumentation';
@ -76,7 +76,6 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
screenshot: ['off', { scope: 'worker', option: true }],
video: ['off', { scope: 'worker', option: true }],
trace: ['off', { scope: 'worker', option: true }],
pageSnapshot: ['only-on-failure', { scope: 'worker', option: true }],
_browserOptions: [async ({ playwright, headless, channel, launchOptions }, use) => {
const options: LaunchOptions = {
@ -244,12 +243,13 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
playwright._defaultContextNavigationTimeout = undefined;
}, { auto: 'all-hooks-included', title: 'context configuration', box: true } as any],
_setupArtifacts: [async ({ playwright, screenshot, pageSnapshot }, use, testInfo) => {
_setupArtifacts: [async ({ playwright, screenshot }, use, testInfo) => {
// This fixture has a separate zero-timeout slot to ensure that artifact collection
// happens even after some fixtures or hooks time out.
// Now that default test timeout is known, we can replace zero with an actual value.
testInfo.setTimeout(testInfo.project.timeout);
const pageSnapshot = process.env.PLAYWRIGHT_COPY_PROMPT ? 'on' : 'off';
const artifactsRecorder = new ArtifactsRecorder(playwright, tracing().artifactsDir(), screenshot, pageSnapshot);
await artifactsRecorder.willStartTest(testInfo as TestInfoImpl);
@ -519,6 +519,8 @@ function connectOptionsFromEnv() {
};
}
type SnapshotRecorderMode = 'on' | 'off' | 'only-on-failure' | 'on-first-failure';
class SnapshotRecorder {
private _ordinal = 0;
private _temporary: string[] = [];
@ -526,7 +528,7 @@ class SnapshotRecorder {
constructor(
private _artifactsRecorder: ArtifactsRecorder,
private _mode: ScreenshotMode | PageSnapshotMode,
private _mode: SnapshotRecorderMode,
private _name: string,
private _contentType: string,
private _extension: string,
@ -618,7 +620,7 @@ class ArtifactsRecorder {
private _pageSnapshotRecorder: SnapshotRecorder;
private _screenshotRecorder: SnapshotRecorder;
constructor(playwright: PlaywrightImpl, artifactsDir: string, screenshot: ScreenshotOption, pageSnapshot: PageSnapshotMode) {
constructor(playwright: PlaywrightImpl, artifactsDir: string, screenshot: ScreenshotOption, pageSnapshot: SnapshotRecorderMode) {
this._playwright = playwright;
this._artifactsDir = artifactsDir;
const screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;

View File

@ -96,7 +96,6 @@ export interface TestServerInterface {
workers?: number | string;
updateSnapshots?: 'all' | 'changed' | 'missing' | 'none';
updateSourceMethod?: 'overwrite' | 'patch' | '3way';
pageSnapshot?: 'off' | 'on' | 'only-on-failure';
reporters?: string[],
trace?: 'on' | 'off';
video?: 'on' | 'off';

View File

@ -312,7 +312,6 @@ export class TestServerDispatcher implements TestServerInterface {
...(params.trace === 'off' ? { trace: 'off' } : {}),
...(params.video === 'on' || params.video === 'off' ? { video: params.video } : {}),
...(params.headed !== undefined ? { headless: !params.headed } : {}),
...(params.pageSnapshot ? { pageSnapshot: params.pageSnapshot } : undefined),
_optionContextReuseMode: params.reuseContext ? 'when-possible' : undefined,
_optionConnectOptions: params.connectWsEndpoint ? { wsEndpoint: params.connectWsEndpoint } : undefined,
},

View File

@ -6170,27 +6170,6 @@ export interface PlaywrightWorkerOptions {
* Learn more about [automatic screenshots](https://playwright.dev/docs/test-use-options#recording-options).
*/
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
/**
* Whether to automatically capture a ARIA snapshot of the page after each test. Defaults to `'only-on-failure'`.
* - `'off'`: Do not capture page snapshots.
* - `'on'`: Capture page snapshot after each test.
* - `'only-on-failure'`: Capture page snapshot after each test failure.
*
* **Usage**
*
* ```js
* // playwright.config.ts
* import { defineConfig } from '@playwright/test';
*
* export default defineConfig({
* use: {
* pageSnapshot: 'on',
* },
* });
* ```
*
*/
pageSnapshot: PageSnapshotMode;
/**
* Whether to record trace for each test. Defaults to `'off'`.
* - `'off'`: Do not record trace.
@ -6250,7 +6229,6 @@ export interface PlaywrightWorkerOptions {
}
export type ScreenshotMode = 'off' | 'on' | 'only-on-failure' | 'on-first-failure';
export type PageSnapshotMode = 'off' | 'on' | 'only-on-failure';
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' | 'retain-on-first-failure';
export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';

View File

@ -97,6 +97,9 @@ const CopyPromptButton: React.FC<{
[error, diff, codeFrame, pageSnapshot]
);
if (!pageSnapshot)
return;
return (
<CopyToClipboardTextButton
value={prompt}

View File

@ -128,7 +128,7 @@ test('should work with screenshot: on', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { screenshot: 'on', pageSnapshot: 'off' } };
module.exports = { use: { screenshot: 'on' } };
`,
}, { workers: 1 });
@ -168,7 +168,7 @@ test('should work with screenshot: only-on-failure', async ({ runInlineTest }, t
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { screenshot: 'only-on-failure', pageSnapshot: 'off' } };
module.exports = { use: { screenshot: 'only-on-failure' } };
`,
}, { workers: 1 });
@ -204,7 +204,7 @@ test('should work with screenshot: on-first-failure', async ({ runInlineTest },
'playwright.config.ts': `
module.exports = {
retries: 1,
use: { screenshot: 'on-first-failure', pageSnapshot: 'off' }
use: { screenshot: 'on-first-failure' }
};
`,
}, { workers: 1 });
@ -231,7 +231,7 @@ test('should work with screenshot: only-on-failure & fullPage', async ({ runInli
});
`,
'playwright.config.ts': `
module.exports = { use: { screenshot: { mode: 'only-on-failure', fullPage: true }, pageSnapshot: 'off' } };
module.exports = { use: { screenshot: { mode: 'only-on-failure', fullPage: true } } };
`,
}, { workers: 1 });
expect(result.exitCode).toBe(1);
@ -252,7 +252,7 @@ test('should work with trace: on', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { trace: 'on', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'on' } };
`,
}, { workers: 1 });
@ -288,7 +288,7 @@ test('should work with trace: retain-on-failure', async ({ runInlineTest }, test
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { trace: 'retain-on-failure', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'retain-on-failure' } };
`,
}, { workers: 1 });
@ -314,7 +314,7 @@ test('should work with trace: on-first-retry', async ({ runInlineTest }, testInf
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { trace: 'on-first-retry', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'on-first-retry' } };
`,
}, { workers: 1, retries: 1 });
@ -340,7 +340,7 @@ test('should work with trace: on-all-retries', async ({ runInlineTest }, testInf
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { trace: 'on-all-retries', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'on-all-retries' } };
`,
}, { workers: 1, retries: 2 });
@ -376,7 +376,7 @@ test('should work with trace: retain-on-first-failure', async ({ runInlineTest }
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { trace: 'retain-on-first-failure', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'retain-on-first-failure' } };
`,
}, { workers: 1, retries: 2 });
@ -421,13 +421,10 @@ test('should take screenshot when page is closed in afterEach', async ({ runInli
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-fails', 'test-failed-1.png'))).toBeTruthy();
});
test('should work with pageSnapshot: on', async ({ runInlineTest }, testInfo) => {
test('should attach pageSnapshot with PLAYWRIGHT_COPY_PROMPT', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { pageSnapshot: 'on' } };
`,
}, { workers: 1 });
}, { workers: 1 }, { PLAYWRIGHT_COPY_PROMPT: '1' });
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(5);
@ -460,31 +457,3 @@ test('should work with pageSnapshot: on', async ({ runInlineTest }, testInfo) =>
' test-failed-2.aria.yml',
]);
});
test('should work with pageSnapshot: only-on-failure', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
...testFiles,
'playwright.config.ts': `
module.exports = { use: { pageSnapshot: 'only-on-failure' } };
`,
}, { workers: 1 });
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(5);
expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing',
' test-failed-1.aria.yml',
'artifacts-own-context-failing',
' test-failed-1.aria.yml',
'artifacts-persistent-failing',
' test-failed-1.aria.yml',
'artifacts-shared-shared-failing',
' test-failed-1.aria.yml',
' test-failed-2.aria.yml',
'artifacts-two-contexts-failing',
' test-failed-1.aria.yml',
' test-failed-2.aria.yml',
]);
});

View File

@ -221,7 +221,6 @@ test('should record trace', async ({ runInlineTest }) => {
'browserContext.newPage',
'expect.toBe',
'After Hooks',
'locator.ariaSnapshot',
'fixture: page',
'fixture: context',
'Worker Cleanup',

View File

@ -485,7 +485,7 @@ test('should work with video: retain-on-failure', async ({ runInlineTest }) => {
test('should work with video: on-first-retry', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: { video: 'on-first-retry', pageSnapshot: 'off' }, retries: 1, name: 'chromium' };
module.exports = { use: { video: 'on-first-retry' }, retries: 1, name: 'chromium' };
`,
'a.test.ts': `
import { test, expect } from '@playwright/test';

View File

@ -59,7 +59,7 @@ test('should stop tracing with trace: on-first-retry, when not retrying', async
test('should record api trace', async ({ runInlineTest, server }, testInfo) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: { trace: 'on', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'on' } };
`,
'a.spec.ts': `
import { test, expect } from '@playwright/test';
@ -290,7 +290,7 @@ test('should work in serial mode', async ({ runInlineTest }, testInfo) => {
test('should not override trace file in afterAll', async ({ runInlineTest, server }, testInfo) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: { trace: 'retain-on-failure', pageSnapshot: 'off' } };
module.exports = { use: { trace: 'retain-on-failure' } };
`,
'a.spec.ts': `
import { test, expect } from '@playwright/test';
@ -642,7 +642,7 @@ test('should expand expect.toPass', async ({ runInlineTest }, testInfo) => {
test('should show non-expect error in trace', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: { trace: { mode: 'on' }, pageSnapshot: 'off' } };
module.exports = { use: { trace: { mode: 'on' } } };
`,
'a.spec.ts': `
import { test, expect } from '@playwright/test';
@ -850,7 +850,7 @@ test('should record nested steps, even after timeout', async ({ runInlineTest },
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = {
use: { trace: { mode: 'on' }, pageSnapshot: 'off' },
use: { trace: { mode: 'on' } },
timeout: 5000,
};
`,
@ -1156,9 +1156,6 @@ test('should record trace for manually created context in a failed test', async
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/31541' });
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: { pageSnapshot: 'off' } };
`,
'a.spec.ts': `
import { test, expect } from '@playwright/test';
test('fail', async ({ browser }) => {
@ -1237,9 +1234,6 @@ test('should record trace after fixture teardown timeout', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/30718' },
}, async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { use: { pageSnapshot: 'off' } };
`,
'a.spec.ts': `
import { test as base, expect } from '@playwright/test';
const test = base.extend({

View File

@ -2805,6 +2805,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
GITHUB_SHA: 'example-sha',
GITHUB_REF_NAME: '42/merge',
GITHUB_BASE_REF: 'HEAD~1',
PLAYWRIGHT_COPY_PROMPT: '1',
});
expect(result.exitCode).toBe(1);

View File

@ -192,9 +192,6 @@ test('should not report nested after hooks', async ({ runInlineTest }) => {
'playwright.config.ts': `
module.exports = {
reporter: './reporter',
use: {
pageSnapshot: 'off',
}
};
`,
'a.test.ts': `
@ -580,9 +577,6 @@ test('should not mark page.close as failed when page.click fails', async ({ runI
'playwright.config.ts': `
module.exports = {
reporter: './reporter',
use: {
pageSnapshot: 'off',
}
};
`,
'a.test.ts': `
@ -1236,9 +1230,6 @@ test('should report api step failure', async ({ runInlineTest }) => {
'playwright.config.ts': `
module.exports = {
reporter: './reporter',
use: {
pageSnapshot: 'off',
}
};
`,
'a.test.ts': `

View File

@ -619,9 +619,6 @@ test('should write missing expectations locally twice and attach them', async ({
const result = await runInlineTest({
...playwrightConfig({
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
use: {
pageSnapshot: 'off',
},
}),
'a.spec.js': `
const { test, expect } = require('@playwright/test');
@ -693,9 +690,6 @@ test('should attach missing expectations to right step', async ({ runInlineTest
`,
...playwrightConfig({
reporter: [['dot'], ['./reporter']],
use: {
pageSnapshot: 'off',
}
}),
'a.spec.js': `
const { test, expect } = require('@playwright/test');
@ -1126,9 +1120,6 @@ test('should attach expected/actual/diff when sizes are different', async ({ run
const result = await runInlineTest({
...playwrightConfig({
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
use: {
pageSnapshot: 'off',
},
}),
'__screenshots__/a.spec.js/snapshot.png': createImage(2, 2),
'a.spec.js': `
@ -1387,9 +1378,6 @@ test('should trim+sanitize attachment names and paths', async ({ runInlineTest }
const result = await runInlineTest({
...playwrightConfig({
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
use: {
pageSnapshot: 'off',
}
}),
'a.spec.js': `
const { test, expect } = require('@playwright/test');

View File

@ -46,6 +46,7 @@ test('openai', async ({ runUITest, server }) => {
}, {
EXPERIMENTAL_OPENAI_API_KEY: 'fake-key',
OPENAI_BASE_URL: server.PREFIX,
PLAYWRIGHT_COPY_PROMPT: '1',
});
await page.getByTitle('Run all').click();
@ -86,6 +87,7 @@ test('anthropic', async ({ runUITest, server }) => {
}, {
EXPERIMENTAL_ANTHROPIC_API_KEY: 'fake-key',
ANTHROPIC_BASE_URL: server.PREFIX,
PLAYWRIGHT_COPY_PROMPT: '1',
});
await page.getByTitle('Run all').click();

View File

@ -504,11 +504,12 @@ test('should show copy prompt button in errors tab', async ({ runUITest }) => {
const { page } = await runUITest({
'a.spec.ts': `
import { test, expect } from '@playwright/test';
test('fails', async () => {
test('fails', async ({ page }) => {
await page.setContent('<button>Submit</button>');
expect(1).toBe(2);
});
`.trim(),
});
}, { PLAYWRIGHT_COPY_PROMPT: '1' });
await page.getByText('fails').dblclick();
@ -518,10 +519,10 @@ test('fails', async () => {
const prompt = await page.evaluate(() => navigator.clipboard.readText());
expect(prompt, 'contains error').toContain('expect(received).toBe(expected)');
expect(prompt.replaceAll('\r\n', '\n'), 'contains codeframe').toContain(`
1 | import { test, expect } from '@playwright/test';
2 | test('fails', async () => {
> 3 | expect(1).toBe(2);
2 | test('fails', async ({ page }) => {
3 | await page.setContent('<button>Submit</button>');
> 4 | expect(1).toBe(2);
^
4 | });
5 | });
`.trim());
});

View File

@ -234,13 +234,11 @@ export interface PlaywrightWorkerOptions {
launchOptions: Omit<LaunchOptions, 'tracesDir'>;
connectOptions: ConnectOptions | undefined;
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
pageSnapshot: PageSnapshotMode;
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean, attachments?: boolean };
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
}
export type ScreenshotMode = 'off' | 'on' | 'only-on-failure' | 'on-first-failure';
export type PageSnapshotMode = 'off' | 'on' | 'only-on-failure';
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' | 'retain-on-first-failure';
export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';