feat: screenshot:on-first-failure (#33266)
This commit is contained in:
parent
1950bbdc6e
commit
2e01154bb5
|
@ -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**
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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': `
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue