feat: allow options in automatic screenshots (#19143)
Closes #9983 Allowing Automatic Screenshots in `PlaywrightTestConfig` to have `fullPage` & `omitBackground` as optional parameters.
This commit is contained in:
parent
cac67fb94f
commit
cd4ccdfa29
|
|
@ -190,7 +190,10 @@ Learn more about [various timeouts](../test-timeouts.md).
|
||||||
|
|
||||||
## property: TestOptions.screenshot
|
## property: TestOptions.screenshot
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: <[Screenshot]<"off"|"on"|"only-on-failure">>
|
- type: <[Object]|[ScreenshotMode]<"off"|"on"||"only-on-failure">>
|
||||||
|
- `mode` <[ScreenshotMode]<"off"|"on"|"only-on-failure">> Automatic screenshot mode.
|
||||||
|
- `fullPage` ?<[boolean]> When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to `false`.
|
||||||
|
- `omitBackground` ?<[boolean]> Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. Defaults to `false`.
|
||||||
|
|
||||||
Whether to automatically capture a screenshot after each test. Defaults to `'off'`.
|
Whether to automatically capture a screenshot after each test. Defaults to `'off'`.
|
||||||
* `'off'`: Do not capture screenshots.
|
* `'off'`: Do not capture screenshots.
|
||||||
|
|
|
||||||
|
|
@ -255,6 +255,8 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
if (debugMode())
|
if (debugMode())
|
||||||
testInfo.setTimeout(0);
|
testInfo.setTimeout(0);
|
||||||
|
|
||||||
|
const screenshotOptions = typeof screenshot !== 'string' ? { fullPage: screenshot.fullPage, omitBackground: screenshot.omitBackground } : undefined;
|
||||||
|
const screenshotMode = typeof screenshot === 'string' ? screenshot : screenshot.mode;
|
||||||
const traceMode = normalizeTraceMode(trace);
|
const traceMode = normalizeTraceMode(trace);
|
||||||
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
|
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
|
||||||
const traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
const traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
||||||
|
|
@ -342,7 +344,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
temporaryScreenshots.push(screenshotPath);
|
temporaryScreenshots.push(screenshotPath);
|
||||||
// Pass caret=initial to avoid any evaluations that might slow down the screenshot
|
// Pass caret=initial to avoid any evaluations that might slow down the screenshot
|
||||||
// and let the page modify itself from the problematic state it had at the moment of failure.
|
// and let the page modify itself from the problematic state it had at the moment of failure.
|
||||||
await page.screenshot({ timeout: 5000, path: screenshotPath, caret: 'initial' }).catch(() => {});
|
await page.screenshot({ ...screenshotOptions, timeout: 5000, path: screenshotPath, caret: 'initial' }).catch(() => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
const screenshotOnTestFailure = async () => {
|
const screenshotOnTestFailure = async () => {
|
||||||
|
|
@ -354,7 +356,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
|
|
||||||
const onWillCloseContext = async (context: BrowserContext) => {
|
const onWillCloseContext = async (context: BrowserContext) => {
|
||||||
await stopTracing(context.tracing);
|
await stopTracing(context.tracing);
|
||||||
if (screenshot === 'on' || screenshot === 'only-on-failure') {
|
if (screenshotMode === 'on' || screenshotMode === 'only-on-failure') {
|
||||||
// Capture screenshot for now. We'll know whether we have to preserve them
|
// Capture screenshot for now. We'll know whether we have to preserve them
|
||||||
// after the test finishes.
|
// after the test finishes.
|
||||||
await Promise.all(context.pages().map(screenshotPage));
|
await Promise.all(context.pages().map(screenshotPage));
|
||||||
|
|
@ -380,7 +382,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
const existingApiRequests: APIRequestContext[] = Array.from((playwright.request as any)._contexts as Set<APIRequestContext>);
|
const existingApiRequests: APIRequestContext[] = Array.from((playwright.request as any)._contexts as Set<APIRequestContext>);
|
||||||
await Promise.all(existingApiRequests.map(onDidCreateRequestContext));
|
await Promise.all(existingApiRequests.map(onDidCreateRequestContext));
|
||||||
}
|
}
|
||||||
if (screenshot === 'on' || screenshot === 'only-on-failure')
|
if (screenshotMode === 'on' || screenshotMode === 'only-on-failure')
|
||||||
testInfoImpl._onTestFailureImmediateCallbacks.set(screenshotOnTestFailure, 'Screenshot on failure');
|
testInfoImpl._onTestFailureImmediateCallbacks.set(screenshotOnTestFailure, 'Screenshot on failure');
|
||||||
|
|
||||||
// 2. Run the test.
|
// 2. Run the test.
|
||||||
|
|
@ -389,7 +391,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
// 3. Determine whether we need the artifacts.
|
// 3. Determine whether we need the artifacts.
|
||||||
const testFailed = testInfo.status !== testInfo.expectedStatus;
|
const testFailed = testInfo.status !== testInfo.expectedStatus;
|
||||||
const preserveTrace = captureTrace && (traceMode === 'on' || (testFailed && traceMode === 'retain-on-failure') || (traceMode === 'on-first-retry' && testInfo.retry === 1));
|
const preserveTrace = captureTrace && (traceMode === 'on' || (testFailed && traceMode === 'retain-on-failure') || (traceMode === 'on-first-retry' && testInfo.retry === 1));
|
||||||
const captureScreenshots = (screenshot === 'on' || (screenshot === 'only-on-failure' && testFailed));
|
const captureScreenshots = screenshotMode === 'on' || (screenshotMode === 'only-on-failure' && testFailed);
|
||||||
|
|
||||||
const traceAttachments: string[] = [];
|
const traceAttachments: string[] = [];
|
||||||
const addTraceAttachment = () => {
|
const addTraceAttachment = () => {
|
||||||
|
|
@ -446,7 +448,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
return;
|
return;
|
||||||
// Pass caret=initial to avoid any evaluations that might slow down the screenshot
|
// Pass caret=initial to avoid any evaluations that might slow down the screenshot
|
||||||
// and let the page modify itself from the problematic state it had at the moment of failure.
|
// and let the page modify itself from the problematic state it had at the moment of failure.
|
||||||
await page.screenshot({ timeout: 5000, path: addScreenshotAttachment(), caret: 'initial' }).catch(() => {});
|
await page.screenshot({ ...screenshotOptions, timeout: 5000, path: addScreenshotAttachment(), caret: 'initial' }).catch(() => {});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}).concat(leftoverApiRequests.map(async context => {
|
}).concat(leftoverApiRequests.map(async context => {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse } from 'playwright-core';
|
import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse, PageScreenshotOptions } from 'playwright-core';
|
||||||
export * from 'playwright-core';
|
export * from 'playwright-core';
|
||||||
|
|
||||||
export type ReporterDescription =
|
export type ReporterDescription =
|
||||||
|
|
@ -2965,7 +2965,7 @@ export interface PlaywrightWorkerOptions {
|
||||||
*
|
*
|
||||||
* Learn more about [automatic screenshots](https://playwright.dev/docs/test-configuration#automatic-screenshots).
|
* Learn more about [automatic screenshots](https://playwright.dev/docs/test-configuration#automatic-screenshots).
|
||||||
*/
|
*/
|
||||||
screenshot: 'off' | 'on' | 'only-on-failure';
|
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
|
||||||
/**
|
/**
|
||||||
* Whether to record trace for each test. Defaults to `'off'`.
|
* Whether to record trace for each test. Defaults to `'off'`.
|
||||||
* - `'off'`: Do not record trace.
|
* - `'off'`: Do not record trace.
|
||||||
|
|
@ -2995,6 +2995,7 @@ export interface PlaywrightWorkerOptions {
|
||||||
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
|
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ScreenshotMode = 'off' | 'on' | 'only-on-failure';
|
||||||
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
||||||
export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Page, ViewportSize } from 'playwright-core';
|
import type { Page, ViewportSize } from 'playwright-core';
|
||||||
import type { VideoMode } from '@playwright/test';
|
import type { PageScreenshotOptions, ScreenshotMode, VideoMode } from '@playwright/test';
|
||||||
export { expect } from '@playwright/test';
|
export { expect } from '@playwright/test';
|
||||||
|
|
||||||
// Page test does not guarantee an isolated context, just a new page (because Android).
|
// Page test does not guarantee an isolated context, just a new page (because Android).
|
||||||
|
|
@ -26,6 +26,7 @@ export type PageTestFixtures = {
|
||||||
export type PageWorkerFixtures = {
|
export type PageWorkerFixtures = {
|
||||||
headless: boolean;
|
headless: boolean;
|
||||||
channel: string;
|
channel: string;
|
||||||
|
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
|
||||||
trace: 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | /** deprecated */ 'retry-with-trace';
|
trace: 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | /** deprecated */ 'retry-with-trace';
|
||||||
video: VideoMode | { mode: VideoMode, size: ViewportSize };
|
video: VideoMode | { mode: VideoMode, size: ViewportSize };
|
||||||
browserName: 'chromium' | 'firefox' | 'webkit';
|
browserName: 'chromium' | 'firefox' | 'webkit';
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
|
|
@ -189,6 +189,35 @@ test('should work with screenshot: only-on-failure', async ({ runInlineTest }, t
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should work with screenshot: only-on-failure & fullPage', async ({ runInlineTest, server }, testInfo) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'artifacts.spec.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
|
||||||
|
test('should fail and take fullPage screenshots', async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 500, height: 500 });
|
||||||
|
await page.goto('${server.PREFIX}/grid.html');
|
||||||
|
expect(1).toBe(2);
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'playwright.config.ts': `
|
||||||
|
module.exports = { use: { screenshot: { mode: 'only-on-failure', fullPage: true } } };
|
||||||
|
`,
|
||||||
|
}, { workers: 1 });
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.passed).toBe(0);
|
||||||
|
expect(result.failed).toBe(1);
|
||||||
|
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
|
||||||
|
'artifacts-should-fail-and-take-fullPage-screenshots',
|
||||||
|
' test-failed-1.png',
|
||||||
|
'report.json',
|
||||||
|
]);
|
||||||
|
const screenshotFailure = fs.readFileSync(
|
||||||
|
testInfo.outputPath('test-results', 'artifacts-should-fail-and-take-fullPage-screenshots', 'test-failed-1.png')
|
||||||
|
);
|
||||||
|
expect.soft(screenshotFailure).toMatchSnapshot('screenshot-grid-fullpage.png');
|
||||||
|
});
|
||||||
|
|
||||||
test('should work with trace: on', async ({ runInlineTest }, testInfo) => {
|
test('should work with trace: on', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...testFiles,
|
...testFiles,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse } from 'playwright-core';
|
import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse, PageScreenshotOptions } from 'playwright-core';
|
||||||
export * from 'playwright-core';
|
export * from 'playwright-core';
|
||||||
|
|
||||||
export type ReporterDescription =
|
export type ReporterDescription =
|
||||||
|
|
@ -208,11 +208,12 @@ export interface PlaywrightWorkerOptions {
|
||||||
channel: BrowserChannel | undefined;
|
channel: BrowserChannel | undefined;
|
||||||
launchOptions: LaunchOptions;
|
launchOptions: LaunchOptions;
|
||||||
connectOptions: ConnectOptions | undefined;
|
connectOptions: ConnectOptions | undefined;
|
||||||
screenshot: 'off' | 'on' | 'only-on-failure';
|
screenshot: ScreenshotMode | { mode: ScreenshotMode } & Pick<PageScreenshotOptions, 'fullPage' | 'omitBackground'>;
|
||||||
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean };
|
trace: TraceMode | /** deprecated */ 'retry-with-trace' | { mode: TraceMode, snapshots?: boolean, screenshots?: boolean, sources?: boolean };
|
||||||
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
|
video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ScreenshotMode = 'off' | 'on' | 'only-on-failure';
|
||||||
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
||||||
export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue