feat: screenshot:on-first-failure (#33266)

This commit is contained in:
Dmitry Gozman 2024-10-24 04:41:35 -07:00 committed by GitHub
parent 1950bbdc6e
commit 2e01154bb5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 42 additions and 8 deletions

View File

@ -479,8 +479,8 @@ export default defineConfig({
## property: TestOptions.screenshot ## property: TestOptions.screenshot
* since: v1.10 * since: v1.10
- type: <[Object]|[ScreenshotMode]<"off"|"on"|"only-on-failure">> - type: <[Object]|[ScreenshotMode]<"off"|"on"|"only-on-failure"|"on-first-failure">>
- `mode` <[ScreenshotMode]<"off"|"on"|"only-on-failure">> Automatic screenshot mode. - `mode` <[ScreenshotMode]<"off"|"on"|"only-on-failure"|"on-first-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`. - `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`. - `omitBackground` ?<[boolean]> Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. Defaults to `false`.
@ -488,6 +488,7 @@ Whether to automatically capture a screenshot after each test. Defaults to `'off
* `'off'`: Do not capture screenshots. * `'off'`: Do not capture screenshots.
* `'on'`: Capture screenshot after each test. * `'on'`: Capture screenshot after each test.
* `'only-on-failure'`: Capture screenshot after each test failure. * `'only-on-failure'`: Capture screenshot after each test failure.
* `'on-first-failure'`: Capture screenshot after each test's first failure.
**Usage** **Usage**

View File

@ -571,7 +571,7 @@ class ArtifactsRecorder {
if (this._reusedContexts.has(context)) if (this._reusedContexts.has(context))
return; return;
await this._stopTracing(context.tracing); await this._stopTracing(context.tracing);
if (this._screenshotMode === 'on' || this._screenshotMode === 'only-on-failure') { if (this._screenshotMode === 'on' || this._screenshotMode === 'only-on-failure' || (this._screenshotMode === 'on-first-failure' && this._testInfo.retry === 0)) {
// 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(page => this._screenshotPage(page, true))); await Promise.all(context.pages().map(page => this._screenshotPage(page, true)));
@ -588,14 +588,19 @@ class ArtifactsRecorder {
await this._stopTracing(tracing); await this._stopTracing(tracing);
} }
private _shouldCaptureScreenshotUponFinish() {
return this._screenshotMode === 'on' ||
(this._screenshotMode === 'only-on-failure' && this._testInfo._isFailure()) ||
(this._screenshotMode === 'on-first-failure' && this._testInfo._isFailure() && this._testInfo.retry === 0);
}
async didFinishTestFunction() { async didFinishTestFunction() {
const captureScreenshots = this._screenshotMode === 'on' || (this._screenshotMode === 'only-on-failure' && this._testInfo._isFailure()); if (this._shouldCaptureScreenshotUponFinish())
if (captureScreenshots)
await this._screenshotOnTestFailure(); await this._screenshotOnTestFailure();
} }
async didFinishTest() { async didFinishTest() {
const captureScreenshots = this._screenshotMode === 'on' || (this._screenshotMode === 'only-on-failure' && this._testInfo._isFailure()); const captureScreenshots = this._shouldCaptureScreenshotUponFinish();
if (captureScreenshots) if (captureScreenshots)
await this._screenshotOnTestFailure(); await this._screenshotOnTestFailure();

View File

@ -5863,6 +5863,7 @@ export interface PlaywrightWorkerOptions {
* - `'off'`: Do not capture screenshots. * - `'off'`: Do not capture screenshots.
* - `'on'`: Capture screenshot after each test. * - `'on'`: Capture screenshot after each test.
* - `'only-on-failure'`: Capture screenshot after each test failure. * - `'only-on-failure'`: Capture screenshot after each test failure.
* - `'on-first-failure'`: Capture screenshot after each test's first failure.
* *
* **Usage** * **Usage**
* *
@ -5938,7 +5939,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 ScreenshotMode = 'off' | 'on' | 'only-on-failure' | 'on-first-failure';
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' | 'retain-on-first-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'; export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';

View File

@ -192,6 +192,33 @@ test('should work with screenshot: only-on-failure', async ({ runInlineTest }, t
]); ]);
}); });
test('should work with screenshot: on-first-failure', async ({ runInlineTest }, testInfo) => {
const result = await runInlineTest({
'a.spec.ts': `
import { test, expect } from '@playwright/test';
test('fails', async ({ page }) => {
await page.setContent('I am the page');
expect(1).toBe(2);
});
`,
'playwright.config.ts': `
module.exports = {
retries: 1,
use: { screenshot: 'on-first-failure' }
};
`,
}, { workers: 1 });
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'a-fails',
' test-failed-1.png',
]);
});
test('should work with screenshot: only-on-failure & fullPage', async ({ runInlineTest, server }, testInfo) => { test('should work with screenshot: only-on-failure & fullPage', async ({ runInlineTest, server }, testInfo) => {
const result = await runInlineTest({ const result = await runInlineTest({
'artifacts.spec.ts': ` 'artifacts.spec.ts': `

View File

@ -236,7 +236,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 ScreenshotMode = 'off' | 'on' | 'only-on-failure' | 'on-first-failure';
export type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry' | 'on-all-retries' | 'retain-on-first-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'; export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';