mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat: restore toHaveScreenshot as experimental feature (#13549)
- Restore docs. - Make `TestConfig.expect` generated. - Allow experimental properties with "e" marker: `- foo e<float>`.
This commit is contained in:
parent
11179982fc
commit
c86c2e8762
@ -998,6 +998,44 @@ Property value.
|
|||||||
### option: LocatorAssertions.toHaveJSProperty.timeout = %%-js-assertions-timeout-%%
|
### option: LocatorAssertions.toHaveJSProperty.timeout = %%-js-assertions-timeout-%%
|
||||||
### option: LocatorAssertions.toHaveJSProperty.timeout = %%-csharp-java-python-assertions-timeout-%%
|
### option: LocatorAssertions.toHaveJSProperty.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
|
|
||||||
|
|
||||||
|
## async method: LocatorAssertions.toHaveScreenshot
|
||||||
|
* langs: js
|
||||||
|
* experimental
|
||||||
|
|
||||||
|
Ensures that [Locator] resolves to a given screenshot. This function will re-take
|
||||||
|
screenshots until it matches with the saved expectation.
|
||||||
|
|
||||||
|
If there's no expectation yet, it will wait until two consecutive screenshots
|
||||||
|
yield the same result, and save the last one as an expectation.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const locator = page.locator('button');
|
||||||
|
await expect(locator).toHaveScreenshot();
|
||||||
|
```
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%%
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.animations = %%-screenshot-option-animations-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.caret = %%-screenshot-option-caret-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.fonts = %%-screenshot-option-fonts-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.mask = %%-screenshot-option-mask-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.omitBackground = %%-screenshot-option-omit-background-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.scale = %%-screenshot-option-scale-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.maxDiffPixels = %%-assertions-max-diff-pixels-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.maxDiffPixelRatio = %%-assertions-max-diff-pixel-ratio-%%
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toHaveScreenshot.threshold = %%-assertions-threshold-%%
|
||||||
|
|
||||||
|
|
||||||
## async method: LocatorAssertions.toHaveText
|
## async method: LocatorAssertions.toHaveText
|
||||||
* langs:
|
* langs:
|
||||||
- alias-java: hasText
|
- alias-java: hasText
|
||||||
|
|||||||
@ -114,6 +114,47 @@ Expected substring or RegExp.
|
|||||||
### option: PageAssertions.NotToHaveURL.timeout = %%-js-assertions-timeout-%%
|
### option: PageAssertions.NotToHaveURL.timeout = %%-js-assertions-timeout-%%
|
||||||
### option: PageAssertions.NotToHaveURL.timeout = %%-csharp-java-python-assertions-timeout-%%
|
### option: PageAssertions.NotToHaveURL.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
|
|
||||||
|
|
||||||
|
## async method: PageAssertions.toHaveScreenshot
|
||||||
|
* langs: js
|
||||||
|
* experimental
|
||||||
|
|
||||||
|
Ensures that the page resolves to a given screenshot. This function will re-take
|
||||||
|
screenshots until it matches with the saved expectation.
|
||||||
|
|
||||||
|
If there's no expectation yet, it will wait until two consecutive screenshots
|
||||||
|
yield the same result, and save the last one as an expectation.
|
||||||
|
|
||||||
|
```js
|
||||||
|
await expect(page).toHaveScreenshot();
|
||||||
|
```
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.timeout = %%-js-assertions-timeout-%%
|
||||||
|
### option: PageAssertions.toHaveScreenshot.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.animations = %%-screenshot-option-animations-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.caret = %%-screenshot-option-caret-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.clip = %%-screenshot-option-clip-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.fonts = %%-screenshot-option-fonts-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.fullPage = %%-screenshot-option-full-page-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.mask = %%-screenshot-option-mask-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.omitBackground = %%-screenshot-option-omit-background-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.scale = %%-screenshot-option-scale-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.maxDiffPixels = %%-assertions-max-diff-pixels-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.maxDiffPixelRatio = %%-assertions-max-diff-pixel-ratio-%%
|
||||||
|
|
||||||
|
### option: PageAssertions.toHaveScreenshot.threshold = %%-assertions-threshold-%%
|
||||||
|
|
||||||
|
|
||||||
## async method: PageAssertions.toHaveTitle
|
## async method: PageAssertions.toHaveTitle
|
||||||
* langs:
|
* langs:
|
||||||
- alias-java: hasTitle
|
- alias-java: hasTitle
|
||||||
|
|||||||
@ -34,9 +34,17 @@ export default config;
|
|||||||
```
|
```
|
||||||
|
|
||||||
## property: TestConfig.expect
|
## property: TestConfig.expect
|
||||||
- type: <[Object]>
|
- type: ?<[Object]>
|
||||||
- `timeout` <[int]> Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
- `timeout` ?<[int]> Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||||
- `toMatchSnapshot` <[Object]>
|
- `toHaveScreenshot` ?e<[Object]> Configuration for the [`method: PageAssertions.toHaveScreenshot`] method.
|
||||||
|
- `threshold` ?<[float]> an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
- `maxDiffPixelRatio` ?<[float]> an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
- `animations` ?<[ScreenshotAnimations]<"allow"|"disable">> See [`option: animations`] in [`method: Page.screenshot`]. Defaults to `"disable"`.
|
||||||
|
- `caret` ?<[ScreenshotCaret]<"hide"|"initial">> See [`option: caret`] in [`method: Page.screenshot`]. Defaults to `"hide"`.
|
||||||
|
- `fonts` ?<[ScreenshotFonts]<"ready"|"nowait">> See [`option: fonts`] in [`method: Page.screenshot`]. Defaults to `"ready"`.
|
||||||
|
- `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: scale`] in [`method: Page.screenshot`]. Defaults to `"css"`.
|
||||||
|
- `toMatchSnapshot` ?<[Object]> Configuration for the [`method: ScreenshotAssertions.toMatchSnapshot#1`] method.
|
||||||
- `threshold` ?<[float]> an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
- `threshold` ?<[float]> an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
|
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
|
||||||
- `maxDiffPixelRatio` ?<[float]> an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
- `maxDiffPixelRatio` ?<[float]> an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
@ -408,6 +416,42 @@ const config: PlaywrightTestConfig = {
|
|||||||
export default config;
|
export default config;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## property: TestConfig.screenshotsDir
|
||||||
|
* experimental
|
||||||
|
- type: ?<[string]>
|
||||||
|
|
||||||
|
The base directory, relative to the config file, for screenshot files created with [`method: PageAssertions.toHaveScreenshot`]. Defaults to
|
||||||
|
|
||||||
|
```
|
||||||
|
<directory-of-configuration-file>/__screenshots__/<platform name>/<project name>
|
||||||
|
```
|
||||||
|
|
||||||
|
This path will serve as the base directory for each test file screenshot directory. For example, the following test structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
smoke-tests/
|
||||||
|
└── basic.spec.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
will result in the following screenshots folder structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
__screenshots__/
|
||||||
|
└── darwin/
|
||||||
|
├── Mobile Safari/
|
||||||
|
│ └── smoke-tests/
|
||||||
|
│ └── basic.spec.ts/
|
||||||
|
│ └── screenshot-expectation.png
|
||||||
|
└── Desktop Chrome/
|
||||||
|
└── smoke-tests/
|
||||||
|
└── basic.spec.ts/
|
||||||
|
└── screenshot-expectation.png
|
||||||
|
```
|
||||||
|
|
||||||
|
where:
|
||||||
|
* `darwin/` - a platform name folder
|
||||||
|
* `Mobile Safari` and `Desktop Chrome` - project names
|
||||||
|
|
||||||
## property: TestConfig.shard
|
## property: TestConfig.shard
|
||||||
- type: <[Object]>
|
- type: <[Object]>
|
||||||
- `total` <[int]> The total number of shards.
|
- `total` <[int]> The total number of shards.
|
||||||
|
|||||||
@ -105,12 +105,20 @@ export default config;
|
|||||||
```
|
```
|
||||||
|
|
||||||
## property: TestProject.expect
|
## property: TestProject.expect
|
||||||
- type: <[Object]>
|
- type: ?<[Object]>
|
||||||
- `timeout` <[int]> Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
- `timeout` ?<[int]> Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||||
- `toMatchSnapshot` <[Object]>
|
- `toHaveScreenshot` ?e<[Object]> Configuration for the [`method: PageAssertions.toHaveScreenshot`] method.
|
||||||
- `threshold` <[float]> an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
- `threshold` ?<[float]> an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
- `maxDiffPixels` <[int]> an acceptable amount of pixels that could be different, unset by default.
|
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
|
||||||
- `maxDiffPixelRatio` <[float]> an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
- `maxDiffPixelRatio` ?<[float]> an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
- `animations` ?<[ScreenshotAnimations]<"allow"|"disable">> See [`option: animations`] in [`method: Page.screenshot`]. Defaults to `"disable"`.
|
||||||
|
- `caret` ?<[ScreenshotCaret]<"hide"|"initial">> See [`option: caret`] in [`method: Page.screenshot`]. Defaults to `"hide"`.
|
||||||
|
- `fonts` ?<[ScreenshotFonts]<"ready"|"nowait">> See [`option: fonts`] in [`method: Page.screenshot`]. Defaults to `"ready"`.
|
||||||
|
- `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: scale`] in [`method: Page.screenshot`]. Defaults to `"css"`.
|
||||||
|
- `toMatchSnapshot` ?<[Object]> Configuration for the [`method: ScreenshotAssertions.toMatchSnapshot#1`] method.
|
||||||
|
- `threshold` ?<[float]> an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
- `maxDiffPixelRatio` ?<[float]> an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
|
||||||
Configuration for the `expect` assertion library.
|
Configuration for the `expect` assertion library.
|
||||||
|
|
||||||
@ -149,6 +157,43 @@ Any JSON-serializable metadata that will be put directly to the test report.
|
|||||||
Project name is visible in the report and during test execution.
|
Project name is visible in the report and during test execution.
|
||||||
|
|
||||||
|
|
||||||
|
## property: TestProject.screenshotsDir
|
||||||
|
* experimental
|
||||||
|
- type: ?<[string]>
|
||||||
|
|
||||||
|
The base directory, relative to the config file, for screenshot files created with `toHaveScreenshot`. Defaults to
|
||||||
|
|
||||||
|
```
|
||||||
|
<directory-of-configuration-file>/__screenshots__/<platform name>/<project name>
|
||||||
|
```
|
||||||
|
|
||||||
|
This path will serve as the base directory for each test file screenshot directory. For example, the following test structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
smoke-tests/
|
||||||
|
└── basic.spec.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
will result in the following screenshots folder structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
__screenshots__/
|
||||||
|
└── darwin/
|
||||||
|
├── Mobile Safari/
|
||||||
|
│ └── smoke-tests/
|
||||||
|
│ └── basic.spec.ts/
|
||||||
|
│ └── screenshot-expectation.png
|
||||||
|
└── Desktop Chrome/
|
||||||
|
└── smoke-tests/
|
||||||
|
└── basic.spec.ts/
|
||||||
|
└── screenshot-expectation.png
|
||||||
|
```
|
||||||
|
|
||||||
|
where:
|
||||||
|
* `darwin/` - a platform name folder
|
||||||
|
* `Mobile Safari` and `Desktop Chrome` - project names
|
||||||
|
|
||||||
|
|
||||||
## property: TestProject.snapshotDir
|
## property: TestProject.snapshotDir
|
||||||
- type: <[string]>
|
- type: <[string]>
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ import {
|
|||||||
toHaveURL,
|
toHaveURL,
|
||||||
toHaveValue
|
toHaveValue
|
||||||
} from './matchers/matchers';
|
} from './matchers/matchers';
|
||||||
import { toMatchSnapshot, toHaveScreenshot as _toHaveScreenshot } from './matchers/toMatchSnapshot';
|
import { toMatchSnapshot, toHaveScreenshot } from './matchers/toMatchSnapshot';
|
||||||
import type { Expect } from './types';
|
import type { Expect } from './types';
|
||||||
import { currentTestInfo } from './globals';
|
import { currentTestInfo } from './globals';
|
||||||
import { serializeError, captureStackTrace, currentExpectTimeout } from './util';
|
import { serializeError, captureStackTrace, currentExpectTimeout } from './util';
|
||||||
@ -142,7 +142,7 @@ const customMatchers = {
|
|||||||
toHaveURL,
|
toHaveURL,
|
||||||
toHaveValue,
|
toHaveValue,
|
||||||
toMatchSnapshot,
|
toMatchSnapshot,
|
||||||
_toHaveScreenshot,
|
toHaveScreenshot,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Generator = () => any;
|
type Generator = () => any;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
import type { FullConfigInternal, GlobalInfo } from './types';
|
import type { FullConfigInternal, GlobalInfo } from './types';
|
||||||
import { normalizeAndSaveAttachment } from './util';
|
import { normalizeAndSaveAttachment } from './util';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
export class GlobalInfoImpl implements GlobalInfo {
|
export class GlobalInfoImpl implements GlobalInfo {
|
||||||
private _fullConfig: FullConfigInternal;
|
private _fullConfig: FullConfigInternal;
|
||||||
private _attachments: { name: string; path?: string | undefined; body?: Buffer | undefined; contentType: string; }[] = [];
|
private _attachments: { name: string; path?: string | undefined; body?: Buffer | undefined; contentType: string; }[] = [];
|
||||||
|
|||||||
@ -25,8 +25,8 @@ import * as path from 'path';
|
|||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { ProjectImpl } from './project';
|
import { ProjectImpl } from './project';
|
||||||
import type { Reporter } from '../types/testReporter';
|
|
||||||
import type { BuiltInReporter } from './runner';
|
import type { BuiltInReporter } from './runner';
|
||||||
|
import type { Reporter } from '../types/testReporter';
|
||||||
import { builtInReporters } from './runner';
|
import { builtInReporters } from './runner';
|
||||||
import { isRegExp } from 'playwright-core/lib/utils';
|
import { isRegExp } from 'playwright-core/lib/utils';
|
||||||
import { serializeError } from './util';
|
import { serializeError } from './util';
|
||||||
@ -92,8 +92,8 @@ export class Loader {
|
|||||||
config.testDir = path.resolve(configDir, config.testDir);
|
config.testDir = path.resolve(configDir, config.testDir);
|
||||||
if (config.outputDir !== undefined)
|
if (config.outputDir !== undefined)
|
||||||
config.outputDir = path.resolve(configDir, config.outputDir);
|
config.outputDir = path.resolve(configDir, config.outputDir);
|
||||||
if ((config as any)._screenshotsDir !== undefined)
|
if ((config as any).screenshotsDir !== undefined)
|
||||||
(config as any)._screenshotsDir = path.resolve(configDir, (config as any)._screenshotsDir);
|
(config as any).screenshotsDir = path.resolve(configDir, (config as any).screenshotsDir);
|
||||||
if (config.snapshotDir !== undefined)
|
if (config.snapshotDir !== undefined)
|
||||||
config.snapshotDir = path.resolve(configDir, config.snapshotDir);
|
config.snapshotDir = path.resolve(configDir, config.snapshotDir);
|
||||||
|
|
||||||
@ -210,8 +210,8 @@ export class Loader {
|
|||||||
projectConfig.testDir = path.resolve(this._configDir, projectConfig.testDir);
|
projectConfig.testDir = path.resolve(this._configDir, projectConfig.testDir);
|
||||||
if (projectConfig.outputDir !== undefined)
|
if (projectConfig.outputDir !== undefined)
|
||||||
projectConfig.outputDir = path.resolve(this._configDir, projectConfig.outputDir);
|
projectConfig.outputDir = path.resolve(this._configDir, projectConfig.outputDir);
|
||||||
if ((projectConfig as any)._screenshotsDir !== undefined)
|
if ((projectConfig as any).screenshotsDir !== undefined)
|
||||||
(projectConfig as any)._screenshotsDir = path.resolve(this._configDir, (projectConfig as any)._screenshotsDir);
|
(projectConfig as any).screenshotsDir = path.resolve(this._configDir, (projectConfig as any).screenshotsDir);
|
||||||
if (projectConfig.snapshotDir !== undefined)
|
if (projectConfig.snapshotDir !== undefined)
|
||||||
projectConfig.snapshotDir = path.resolve(this._configDir, projectConfig.snapshotDir);
|
projectConfig.snapshotDir = path.resolve(this._configDir, projectConfig.snapshotDir);
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ export class Loader {
|
|||||||
const outputDir = takeFirst(this._configOverrides.outputDir, projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
|
const outputDir = takeFirst(this._configOverrides.outputDir, projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
|
||||||
const snapshotDir = takeFirst(this._configOverrides.snapshotDir, projectConfig.snapshotDir, config.snapshotDir, testDir);
|
const snapshotDir = takeFirst(this._configOverrides.snapshotDir, projectConfig.snapshotDir, config.snapshotDir, testDir);
|
||||||
const name = takeFirst(this._configOverrides.name, projectConfig.name, config.name, '');
|
const name = takeFirst(this._configOverrides.name, projectConfig.name, config.name, '');
|
||||||
const screenshotsDir = takeFirst((this._configOverrides as any)._screenshotsDir, (projectConfig as any)._screenshotsDir, (config as any)._screenshotsDir, path.join(testDir, '__screenshots__', process.platform, name));
|
const screenshotsDir = takeFirst((this._configOverrides as any).screenshotsDir, (projectConfig as any).screenshotsDir, (config as any).screenshotsDir, path.join(testDir, '__screenshots__', process.platform, name));
|
||||||
const fullProject: FullProjectInternal = {
|
const fullProject: FullProjectInternal = {
|
||||||
fullyParallel: takeFirst(this._configOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, undefined),
|
fullyParallel: takeFirst(this._configOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, undefined),
|
||||||
expect: takeFirst(this._configOverrides.expect, projectConfig.expect, config.expect, undefined),
|
expect: takeFirst(this._configOverrides.expect, projectConfig.expect, config.expect, undefined),
|
||||||
@ -478,7 +478,6 @@ const baseFullConfig: FullConfigInternal = {
|
|||||||
_globalOutputDir: path.resolve(process.cwd()),
|
_globalOutputDir: path.resolve(process.cwd()),
|
||||||
_configDir: '',
|
_configDir: '',
|
||||||
_testGroupsCount: 0,
|
_testGroupsCount: 0,
|
||||||
_screenshotsDir: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function resolveReporters(reporters: Config['reporter'], rootDir: string): ReporterDescription[]|undefined {
|
function resolveReporters(reporters: Config['reporter'], rootDir: string): ReporterDescription[]|undefined {
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
import type { Locator, Page } from 'playwright-core';
|
import type { Locator, Page } from 'playwright-core';
|
||||||
import type { Page as PageEx } from 'playwright-core/lib/client/page';
|
import type { Page as PageEx } from 'playwright-core/lib/client/page';
|
||||||
import type { Locator as LocatorEx } from 'playwright-core/lib/client/locator';
|
import type { Locator as LocatorEx } from 'playwright-core/lib/client/locator';
|
||||||
import type { Expect } from '../types';
|
import type { Expect, UpdateSnapshots } from '../types';
|
||||||
import { currentTestInfo } from '../globals';
|
import { currentTestInfo } from '../globals';
|
||||||
import type { ImageComparatorOptions, Comparator } from 'playwright-core/lib/utils/comparators';
|
import type { ImageComparatorOptions, Comparator } from 'playwright-core/lib/utils/comparators';
|
||||||
import { getComparator } from 'playwright-core/lib/utils/comparators';
|
import { getComparator } from 'playwright-core/lib/utils/comparators';
|
||||||
@ -26,7 +26,6 @@ import {
|
|||||||
addSuffixToFilePath, serializeError, sanitizeForFilePath,
|
addSuffixToFilePath, serializeError, sanitizeForFilePath,
|
||||||
trimLongString, callLogText, currentExpectTimeout,
|
trimLongString, callLogText, currentExpectTimeout,
|
||||||
expectTypes, captureStackTrace } from '../util';
|
expectTypes, captureStackTrace } from '../util';
|
||||||
import type { UpdateSnapshots } from '../types';
|
|
||||||
import colors from 'colors/safe';
|
import colors from 'colors/safe';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@ -290,10 +289,12 @@ export async function toHaveScreenshot(
|
|||||||
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & HaveScreenshotOptions = {},
|
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & HaveScreenshotOptions = {},
|
||||||
optOptions: HaveScreenshotOptions = {}
|
optOptions: HaveScreenshotOptions = {}
|
||||||
): Promise<SyncExpectationResult> {
|
): Promise<SyncExpectationResult> {
|
||||||
|
if (!process.env.PLAYWRIGHT_EXPERIMENTAL_FEATURES)
|
||||||
|
throw new Error(`To use the experimental method "toHaveScreenshot", set PLAYWRIGHT_EXPERIMENTAL_FEATURES=1 enviroment variable.`);
|
||||||
const testInfo = currentTestInfo();
|
const testInfo = currentTestInfo();
|
||||||
if (!testInfo)
|
if (!testInfo)
|
||||||
throw new Error(`toHaveScreenshot() must be called during the test`);
|
throw new Error(`toHaveScreenshot() must be called during the test`);
|
||||||
const config = (testInfo.project.expect as any)?._toHaveScreenshot;
|
const config = (testInfo.project.expect as any)?.toHaveScreenshot;
|
||||||
const helper = new SnapshotHelper(
|
const helper = new SnapshotHelper(
|
||||||
testInfo, testInfo._screenshotPath.bind(testInfo), 'png',
|
testInfo, testInfo._screenshotPath.bind(testInfo), 'png',
|
||||||
{
|
{
|
||||||
|
|||||||
@ -48,7 +48,6 @@ export interface FullConfigInternal extends FullConfigPublic {
|
|||||||
_globalOutputDir: string;
|
_globalOutputDir: string;
|
||||||
_configDir: string;
|
_configDir: string;
|
||||||
_testGroupsCount: number;
|
_testGroupsCount: number;
|
||||||
_screenshotsDir: string;
|
|
||||||
|
|
||||||
// Overrides the public field.
|
// Overrides the public field.
|
||||||
projects: FullProjectInternal[];
|
projects: FullProjectInternal[];
|
||||||
|
|||||||
132
packages/playwright-test/types/test.d.ts
vendored
132
packages/playwright-test/types/test.d.ts
vendored
@ -36,26 +36,6 @@ export type UpdateSnapshots = 'all' | 'none' | 'missing';
|
|||||||
|
|
||||||
type UseOptions<TestArgs, WorkerArgs> = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] };
|
type UseOptions<TestArgs, WorkerArgs> = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] };
|
||||||
|
|
||||||
type ExpectSettings = {
|
|
||||||
/**
|
|
||||||
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
|
||||||
*/
|
|
||||||
timeout?: number;
|
|
||||||
toMatchSnapshot?: {
|
|
||||||
/** An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between pixels in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
|
||||||
*/
|
|
||||||
threshold?: number,
|
|
||||||
/**
|
|
||||||
* An acceptable amount of pixels that could be different, unset by default.
|
|
||||||
*/
|
|
||||||
maxDiffPixels?: number,
|
|
||||||
/**
|
|
||||||
* An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
|
||||||
*/
|
|
||||||
maxDiffPixelRatio?: number,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
||||||
* configurations. For example, consider running tests against multiple browsers.
|
* configurations. For example, consider running tests against multiple browsers.
|
||||||
@ -116,13 +96,6 @@ type ExpectSettings = {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
interface TestProject {
|
interface TestProject {
|
||||||
/**
|
|
||||||
* Configuration for the `expect` assertion library.
|
|
||||||
*
|
|
||||||
* Use [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect) to change this option for
|
|
||||||
* all projects.
|
|
||||||
*/
|
|
||||||
expect?: ExpectSettings;
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the same
|
* Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the same
|
||||||
* time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same worker
|
* time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same worker
|
||||||
@ -288,7 +261,41 @@ interface TestProject {
|
|||||||
* all projects.
|
* all projects.
|
||||||
*/
|
*/
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
}
|
/**
|
||||||
|
* Configuration for the `expect` assertion library.
|
||||||
|
*
|
||||||
|
* Use [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect) to change this option for
|
||||||
|
* all projects.
|
||||||
|
*/
|
||||||
|
expect?: {
|
||||||
|
/**
|
||||||
|
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the
|
||||||
|
* [screenshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-screenshotassertions#screenshot-assertions-to-match-snapshot-1)
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
toMatchSnapshot?: {
|
||||||
|
/**
|
||||||
|
* an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
};
|
||||||
|
};}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
||||||
@ -687,26 +694,6 @@ interface TestConfig {
|
|||||||
*/
|
*/
|
||||||
workers?: number;
|
workers?: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* // playwright.config.ts
|
|
||||||
* import { PlaywrightTestConfig } from '@playwright/test';
|
|
||||||
*
|
|
||||||
* const config: PlaywrightTestConfig = {
|
|
||||||
* expect: {
|
|
||||||
* timeout: 10000,
|
|
||||||
* toMatchSnapshot: {
|
|
||||||
* maxDiffPixels: 10,
|
|
||||||
* },
|
|
||||||
* },
|
|
||||||
* };
|
|
||||||
* export default config;
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
expect?: ExpectSettings;
|
|
||||||
/**
|
/**
|
||||||
* Any JSON-serializable metadata that will be put directly to the test report.
|
* Any JSON-serializable metadata that will be put directly to the test report.
|
||||||
*/
|
*/
|
||||||
@ -854,7 +841,54 @@ interface TestConfig {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
}
|
/**
|
||||||
|
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* // playwright.config.ts
|
||||||
|
* import { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
*
|
||||||
|
* const config: PlaywrightTestConfig = {
|
||||||
|
* expect: {
|
||||||
|
* timeout: 10000,
|
||||||
|
* toMatchSnapshot: {
|
||||||
|
* maxDiffPixels: 10,
|
||||||
|
* },
|
||||||
|
* },
|
||||||
|
* };
|
||||||
|
* export default config;
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
expect?: {
|
||||||
|
/**
|
||||||
|
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the
|
||||||
|
* [screenshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-screenshotassertions#screenshot-assertions-to-match-snapshot-1)
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
toMatchSnapshot?: {
|
||||||
|
/**
|
||||||
|
* an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
};
|
||||||
|
};}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` or
|
* Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` or
|
||||||
|
|||||||
494
tests/config/experimental.d.ts
vendored
494
tests/config/experimental.d.ts
vendored
@ -16164,26 +16164,6 @@ export type UpdateSnapshots = 'all' | 'none' | 'missing';
|
|||||||
|
|
||||||
type UseOptions<TestArgs, WorkerArgs> = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] };
|
type UseOptions<TestArgs, WorkerArgs> = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] };
|
||||||
|
|
||||||
type ExpectSettings = {
|
|
||||||
/**
|
|
||||||
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
|
||||||
*/
|
|
||||||
timeout?: number;
|
|
||||||
toMatchSnapshot?: {
|
|
||||||
/** An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between pixels in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
|
||||||
*/
|
|
||||||
threshold?: number,
|
|
||||||
/**
|
|
||||||
* An acceptable amount of pixels that could be different, unset by default.
|
|
||||||
*/
|
|
||||||
maxDiffPixels?: number,
|
|
||||||
/**
|
|
||||||
* An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
|
||||||
*/
|
|
||||||
maxDiffPixelRatio?: number,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
||||||
* configurations. For example, consider running tests against multiple browsers.
|
* configurations. For example, consider running tests against multiple browsers.
|
||||||
@ -16244,13 +16224,6 @@ type ExpectSettings = {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
interface TestProject {
|
interface TestProject {
|
||||||
/**
|
|
||||||
* Configuration for the `expect` assertion library.
|
|
||||||
*
|
|
||||||
* Use [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect) to change this option for
|
|
||||||
* all projects.
|
|
||||||
*/
|
|
||||||
expect?: ExpectSettings;
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the same
|
* Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the same
|
||||||
* time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same worker
|
* time. By default, **test files** are run in parallel. Tests in a single file are run in order, in the same worker
|
||||||
@ -16416,7 +16389,124 @@ interface TestProject {
|
|||||||
* all projects.
|
* all projects.
|
||||||
*/
|
*/
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
}
|
/**
|
||||||
|
* Configuration for the `expect` assertion library.
|
||||||
|
*
|
||||||
|
* Use [testConfig.expect](https://playwright.dev/docs/api/class-testconfig#test-config-expect) to change this option for
|
||||||
|
* all projects.
|
||||||
|
*/
|
||||||
|
expect?: {
|
||||||
|
/**
|
||||||
|
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the
|
||||||
|
* [pageAssertions.toHaveScreenshot([options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot)
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
toHaveScreenshot?: {
|
||||||
|
/**
|
||||||
|
* an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `animations` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults
|
||||||
|
* to `"disable"`.
|
||||||
|
*/
|
||||||
|
animations?: "allow"|"disable";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `caret` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults to
|
||||||
|
* `"hide"`.
|
||||||
|
*/
|
||||||
|
caret?: "hide"|"initial";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `fonts` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults to
|
||||||
|
* `"ready"`.
|
||||||
|
*/
|
||||||
|
fonts?: "ready"|"nowait";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `scale` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults to
|
||||||
|
* `"css"`.
|
||||||
|
*/
|
||||||
|
scale?: "css"|"device";
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the
|
||||||
|
* [screenshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-screenshotassertions#screenshot-assertions-to-match-snapshot-1)
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
toMatchSnapshot?: {
|
||||||
|
/**
|
||||||
|
* an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base directory, relative to the config file, for screenshot files created with `toHaveScreenshot`. Defaults to
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* <directory-of-configuration-file>/__screenshots__/<platform name>/<project name>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This path will serve as the base directory for each test file screenshot directory. For example, the following test
|
||||||
|
* structure:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* smoke-tests/
|
||||||
|
* └── basic.spec.ts
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* will result in the following screenshots folder structure:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* __screenshots__/
|
||||||
|
* └── darwin/
|
||||||
|
* ├── Mobile Safari/
|
||||||
|
* │ └── smoke-tests/
|
||||||
|
* │ └── basic.spec.ts/
|
||||||
|
* │ └── screenshot-expectation.png
|
||||||
|
* └── Desktop Chrome/
|
||||||
|
* └── smoke-tests/
|
||||||
|
* └── basic.spec.ts/
|
||||||
|
* └── screenshot-expectation.png
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* where:
|
||||||
|
* - `darwin/` - a platform name folder
|
||||||
|
* - `Mobile Safari` and `Desktop Chrome` - project names
|
||||||
|
*/
|
||||||
|
screenshotsDir?: string;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
* Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple
|
||||||
@ -16815,26 +16905,6 @@ interface TestConfig {
|
|||||||
*/
|
*/
|
||||||
workers?: number;
|
workers?: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* // playwright.config.ts
|
|
||||||
* import { PlaywrightTestConfig } from '@playwright/test';
|
|
||||||
*
|
|
||||||
* const config: PlaywrightTestConfig = {
|
|
||||||
* expect: {
|
|
||||||
* timeout: 10000,
|
|
||||||
* toMatchSnapshot: {
|
|
||||||
* maxDiffPixels: 10,
|
|
||||||
* },
|
|
||||||
* },
|
|
||||||
* };
|
|
||||||
* export default config;
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
expect?: ExpectSettings;
|
|
||||||
/**
|
/**
|
||||||
* Any JSON-serializable metadata that will be put directly to the test report.
|
* Any JSON-serializable metadata that will be put directly to the test report.
|
||||||
*/
|
*/
|
||||||
@ -16982,7 +17052,139 @@ interface TestConfig {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
}
|
/**
|
||||||
|
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* // playwright.config.ts
|
||||||
|
* import { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
*
|
||||||
|
* const config: PlaywrightTestConfig = {
|
||||||
|
* expect: {
|
||||||
|
* timeout: 10000,
|
||||||
|
* toMatchSnapshot: {
|
||||||
|
* maxDiffPixels: 10,
|
||||||
|
* },
|
||||||
|
* },
|
||||||
|
* };
|
||||||
|
* export default config;
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
expect?: {
|
||||||
|
/**
|
||||||
|
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the
|
||||||
|
* [pageAssertions.toHaveScreenshot([options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot)
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
toHaveScreenshot?: {
|
||||||
|
/**
|
||||||
|
* an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `animations` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults
|
||||||
|
* to `"disable"`.
|
||||||
|
*/
|
||||||
|
animations?: "allow"|"disable";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `caret` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults to
|
||||||
|
* `"hide"`.
|
||||||
|
*/
|
||||||
|
caret?: "hide"|"initial";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `fonts` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults to
|
||||||
|
* `"ready"`.
|
||||||
|
*/
|
||||||
|
fonts?: "ready"|"nowait";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `scale` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot). Defaults to
|
||||||
|
* `"css"`.
|
||||||
|
*/
|
||||||
|
scale?: "css"|"device";
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the
|
||||||
|
* [screenshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-screenshotassertions#screenshot-assertions-to-match-snapshot-1)
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
toMatchSnapshot?: {
|
||||||
|
/**
|
||||||
|
* an acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable amount of pixels that could be different, unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base directory, relative to the config file, for screenshot files created with
|
||||||
|
* [pageAssertions.toHaveScreenshot([options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot).
|
||||||
|
* Defaults to
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* <directory-of-configuration-file>/__screenshots__/<platform name>/<project name>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This path will serve as the base directory for each test file screenshot directory. For example, the following test
|
||||||
|
* structure:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* smoke-tests/
|
||||||
|
* └── basic.spec.ts
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* will result in the following screenshots folder structure:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* __screenshots__/
|
||||||
|
* └── darwin/
|
||||||
|
* ├── Mobile Safari/
|
||||||
|
* │ └── smoke-tests/
|
||||||
|
* │ └── basic.spec.ts/
|
||||||
|
* │ └── screenshot-expectation.png
|
||||||
|
* └── Desktop Chrome/
|
||||||
|
* └── smoke-tests/
|
||||||
|
* └── basic.spec.ts/
|
||||||
|
* └── screenshot-expectation.png
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* where:
|
||||||
|
* - `darwin/` - a platform name folder
|
||||||
|
* - `Mobile Safari` and `Desktop Chrome` - project names
|
||||||
|
*/
|
||||||
|
screenshotsDir?: string;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` or
|
* Playwright Test provides many options to configure how your tests are collected and executed, for example `timeout` or
|
||||||
@ -19496,6 +19698,88 @@ interface LocatorAssertions {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
}): Promise<void>;
|
}): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that [Locator] resolves to a given screenshot. This function will re-take screenshots until it matches with the
|
||||||
|
* saved expectation.
|
||||||
|
*
|
||||||
|
* If there's no expectation yet, it will wait until two consecutive screenshots yield the same result, and save the last
|
||||||
|
* one as an expectation.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const locator = page.locator('button');
|
||||||
|
* await expect(locator).toHaveScreenshot();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
toHaveScreenshot(options?: {
|
||||||
|
/**
|
||||||
|
* When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment
|
||||||
|
* depending on their duration:
|
||||||
|
* - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event.
|
||||||
|
* - infinite animations are canceled to initial state, and then played over after the screenshot.
|
||||||
|
*
|
||||||
|
* Defaults to `"allow"` that leaves animations untouched.
|
||||||
|
*/
|
||||||
|
animations?: "disabled"|"allow";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be changed.
|
||||||
|
* Defaults to `"hide"`.
|
||||||
|
*/
|
||||||
|
caret?: "hide"|"initial";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set to `"ready"`, screenshot will wait for
|
||||||
|
* [`document.fonts.ready`](https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready) promise to resolve in all
|
||||||
|
* frames. Defaults to `"nowait"`.
|
||||||
|
*/
|
||||||
|
fonts?: "ready"|"nowait";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box
|
||||||
|
* `#FF00FF` that completely covers its bounding box.
|
||||||
|
*/
|
||||||
|
mask?: Array<Locator>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is
|
||||||
|
* configurable with `TestConfig.expect`. Unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An acceptable amount of pixels that could be different, default is configurable with `TestConfig.expect`. Default is
|
||||||
|
* configurable with `TestConfig.expect`. Unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images.
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
omitBackground?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this will
|
||||||
|
* keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of
|
||||||
|
* high-dpi devices will be twice as large or even larger. Defaults to `"device"`.
|
||||||
|
*/
|
||||||
|
scale?: "css"|"device";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax), default is configurable with `TestConfig.expect`.
|
||||||
|
* Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures the [Locator] points to an element with the given text. You can use regular expressions for the value as well.
|
* Ensures the [Locator] points to an element with the given text. You can use regular expressions for the value as well.
|
||||||
*
|
*
|
||||||
@ -19575,6 +19859,118 @@ interface PageAssertions {
|
|||||||
*/
|
*/
|
||||||
not: PageAssertions;
|
not: PageAssertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the page resolves to a given screenshot. This function will re-take screenshots until it matches with the
|
||||||
|
* saved expectation.
|
||||||
|
*
|
||||||
|
* If there's no expectation yet, it will wait until two consecutive screenshots yield the same result, and save the last
|
||||||
|
* one as an expectation.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* await expect(page).toHaveScreenshot();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
toHaveScreenshot(options?: {
|
||||||
|
/**
|
||||||
|
* When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment
|
||||||
|
* depending on their duration:
|
||||||
|
* - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event.
|
||||||
|
* - infinite animations are canceled to initial state, and then played over after the screenshot.
|
||||||
|
*
|
||||||
|
* Defaults to `"allow"` that leaves animations untouched.
|
||||||
|
*/
|
||||||
|
animations?: "disabled"|"allow";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be changed.
|
||||||
|
* Defaults to `"hide"`.
|
||||||
|
*/
|
||||||
|
caret?: "hide"|"initial";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object which specifies clipping of the resulting image. Should have the following fields:
|
||||||
|
*/
|
||||||
|
clip?: {
|
||||||
|
/**
|
||||||
|
* x-coordinate of top-left corner of clip area
|
||||||
|
*/
|
||||||
|
x: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* y-coordinate of top-left corner of clip area
|
||||||
|
*/
|
||||||
|
y: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* width of clipping area
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* height of clipping area
|
||||||
|
*/
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set to `"ready"`, screenshot will wait for
|
||||||
|
* [`document.fonts.ready`](https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready) promise to resolve in all
|
||||||
|
* frames. Defaults to `"nowait"`.
|
||||||
|
*/
|
||||||
|
fonts?: "ready"|"nowait";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When true, takes a screenshot of the full scrollable page, instead of the currently visible viewport. Defaults to
|
||||||
|
* `false`.
|
||||||
|
*/
|
||||||
|
fullPage?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box
|
||||||
|
* `#FF00FF` that completely covers its bounding box.
|
||||||
|
*/
|
||||||
|
mask?: Array<Locator>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1`. Default is
|
||||||
|
* configurable with `TestConfig.expect`. Unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixelRatio?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An acceptable amount of pixels that could be different, default is configurable with `TestConfig.expect`. Default is
|
||||||
|
* configurable with `TestConfig.expect`. Unset by default.
|
||||||
|
*/
|
||||||
|
maxDiffPixels?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images.
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
omitBackground?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this will
|
||||||
|
* keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of
|
||||||
|
* high-dpi devices will be twice as large or even larger. Defaults to `"device"`.
|
||||||
|
*/
|
||||||
|
scale?: "css"|"device";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the same
|
||||||
|
* pixel in compared images, between zero (strict) and one (lax), default is configurable with `TestConfig.expect`.
|
||||||
|
* Defaults to `0.2`.
|
||||||
|
*/
|
||||||
|
threshold?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures the page has the given title.
|
* Ensures the page has the given title.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -181,7 +181,7 @@ test('should include multiple image diffs', async ({ runInlineTest, page, showRe
|
|||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
module.exports = {
|
module.exports = {
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
use: { viewport: { width: ${IMG_WIDTH}, height: ${IMG_HEIGHT} }}
|
use: { viewport: { width: ${IMG_WIDTH}, height: ${IMG_HEIGHT} }}
|
||||||
};
|
};
|
||||||
`,
|
`,
|
||||||
@ -192,12 +192,12 @@ test('should include multiple image diffs', async ({ runInlineTest, page, showRe
|
|||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('fails', async ({ page }, testInfo) => {
|
test('fails', async ({ page }, testInfo) => {
|
||||||
testInfo.snapshotSuffix = '';
|
testInfo.snapshotSuffix = '';
|
||||||
await expect.soft(page)._toHaveScreenshot({ timeout: 1000 });
|
await expect.soft(page).toHaveScreenshot({ timeout: 1000 });
|
||||||
await expect.soft(page)._toHaveScreenshot({ timeout: 1000 });
|
await expect.soft(page).toHaveScreenshot({ timeout: 1000 });
|
||||||
await expect.soft(page)._toHaveScreenshot({ timeout: 1000 });
|
await expect.soft(page).toHaveScreenshot({ timeout: 1000 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' });
|
}, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never', PLAYWRIGHT_EXPERIMENTAL_FEATURES: '1' });
|
||||||
expect(result.exitCode).toBe(1);
|
expect(result.exitCode).toBe(1);
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
|
|
||||||
@ -260,10 +260,10 @@ test('should include image diff when screenshot failed to generate due to animat
|
|||||||
document.body.textContent = Date.now();
|
document.body.textContent = Date.now();
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
await expect.soft(page)._toHaveScreenshot({ timeout: 1000 });
|
await expect.soft(page).toHaveScreenshot({ timeout: 1000 });
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { 'reporter': 'dot,html', 'update-snapshots': true }, { PW_TEST_HTML_REPORT_OPEN: 'never' });
|
}, { 'reporter': 'dot,html', 'update-snapshots': true }, { PW_TEST_HTML_REPORT_OPEN: 'never', PLAYWRIGHT_EXPERIMENTAL_FEATURES: '1' });
|
||||||
expect(result.exitCode).toBe(1);
|
expect(result.exitCode).toBe(1);
|
||||||
expect(result.failed).toBe(1);
|
expect(result.failed).toBe(1);
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ test('should fail to screenshot a page with infinite animation', async ({ runInl
|
|||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
expect: {
|
expect: {
|
||||||
_toHaveScreenshot: {
|
toHaveScreenshot: {
|
||||||
animations: 'allow',
|
animations: 'allow',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -45,7 +45,7 @@ test('should fail to screenshot a page with infinite animation', async ({ runInl
|
|||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await page.goto('${infiniteAnimationURL}');
|
await page.goto('${infiniteAnimationURL}');
|
||||||
await expect(page)._toHaveScreenshot({ timeout: 2000 });
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -67,7 +67,7 @@ test('should disable animations by default', async ({ runInlineTest }, testInfo)
|
|||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await page.goto('${cssTransitionURL}');
|
await page.goto('${cssTransitionURL}');
|
||||||
await expect(page)._toHaveScreenshot({ timeout: 2000 });
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -76,7 +76,7 @@ test('should disable animations by default', async ({ runInlineTest }, testInfo)
|
|||||||
|
|
||||||
test('should have scale:css by default', async ({ runInlineTest }, testInfo) => {
|
test('should have scale:css by default', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ browser }) => {
|
pwt.test('is a test', async ({ browser }) => {
|
||||||
const context = await browser.newContext({
|
const context = await browser.newContext({
|
||||||
@ -84,7 +84,7 @@ test('should have scale:css by default', async ({ runInlineTest }, testInfo) =>
|
|||||||
deviceScaleFactor: 2,
|
deviceScaleFactor: 2,
|
||||||
});
|
});
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
await context.close();
|
await context.close();
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
@ -95,19 +95,19 @@ test('should have scale:css by default', async ({ runInlineTest }, testInfo) =>
|
|||||||
expect(pngComparator(fs.readFileSync(snapshotOutputPath), whiteImage)).toBe(null);
|
expect(pngComparator(fs.readFileSync(snapshotOutputPath), whiteImage)).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should ignore non-documented options in _toHaveScreenshot config', async ({ runInlineTest }, testInfo) => {
|
test('should ignore non-documented options in toHaveScreenshot config', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
expect: {
|
expect: {
|
||||||
_toHaveScreenshot: {
|
toHaveScreenshot: {
|
||||||
clip: { x: 0, y: 0, width: 10, height: 10 },
|
clip: { x: 0, y: 0, width: 10, height: 10 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -127,17 +127,17 @@ test('screenshotPath should include platform and project name by default', async
|
|||||||
}),
|
}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }, testInfo) => {
|
pwt.test('is a test', async ({ page }, testInfo) => {
|
||||||
await pwt.expect(page)._toHaveScreenshot('snapshot.png');
|
await pwt.expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'foo/b.spec.js': `
|
'foo/b.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }, testInfo) => {
|
pwt.test('is a test', async ({ page }, testInfo) => {
|
||||||
await pwt.expect(page)._toHaveScreenshot('snapshot.png');
|
await pwt.expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
'foo/bar/baz/c.spec.js': `
|
'foo/bar/baz/c.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }, testInfo) => {
|
pwt.test('is a test', async ({ page }, testInfo) => {
|
||||||
await pwt.expect(page)._toHaveScreenshot('snapshot.png');
|
await pwt.expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -147,7 +147,7 @@ test('screenshotPath should include platform and project name by default', async
|
|||||||
expect(fs.existsSync(testInfo.outputPath('__screenshots__', process.platform, PROJECT_NAME, 'foo', 'bar', 'baz', 'c.spec.js', 'snapshot.png'))).toBeTruthy();
|
expect(fs.existsSync(testInfo.outputPath('__screenshots__', process.platform, PROJECT_NAME, 'foo', 'bar', 'baz', 'c.spec.js', 'snapshot.png'))).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should report _toHaveScreenshot step with expectation name in title', async ({ runInlineTest }) => {
|
test('should report toHaveScreenshot step with expectation name in title', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'reporter.ts': `
|
'reporter.ts': `
|
||||||
class Reporter {
|
class Reporter {
|
||||||
@ -161,9 +161,9 @@ test('should report _toHaveScreenshot step with expectation name in title', asyn
|
|||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
// Named expectation.
|
// Named expectation.
|
||||||
await expect(page)._toHaveScreenshot('foo.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('foo.png', { timeout: 2000 });
|
||||||
// Anonymous expectation.
|
// Anonymous expectation.
|
||||||
await expect(page)._toHaveScreenshot({ timeout: 2000 });
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'reporter': '', 'workers': 1, 'update-snapshots': true });
|
}, { 'reporter': '', 'workers': 1, 'update-snapshots': true });
|
||||||
@ -172,8 +172,8 @@ test('should report _toHaveScreenshot step with expectation name in title', asyn
|
|||||||
expect(result.output.split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
expect(result.output.split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
||||||
`%% end browserContext.newPage`,
|
`%% end browserContext.newPage`,
|
||||||
`%% end Before Hooks`,
|
`%% end Before Hooks`,
|
||||||
`%% end expect._toHaveScreenshot(foo.png)`,
|
`%% end expect.toHaveScreenshot(foo.png)`,
|
||||||
`%% end expect._toHaveScreenshot(is-a-test-1.png)`,
|
`%% end expect.toHaveScreenshot(is-a-test-1.png)`,
|
||||||
`%% end browserContext.close`,
|
`%% end browserContext.close`,
|
||||||
`%% end After Hooks`,
|
`%% end After Hooks`,
|
||||||
]);
|
]);
|
||||||
@ -183,14 +183,14 @@ test('should not fail when racing with navigation', async ({ runInlineTest }, te
|
|||||||
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
}),
|
}),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': createImage(10, 10, 255, 0, 0),
|
'__screenshots__/a.spec.js/snapshot.png': createImage(10, 10, 255, 0, 0),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.goto('${infiniteAnimationURL}'),
|
page.goto('${infiniteAnimationURL}'),
|
||||||
expect(page)._toHaveScreenshot({
|
expect(page).toHaveScreenshot({
|
||||||
name: 'snapshot.png',
|
name: 'snapshot.png',
|
||||||
animations: "disabled",
|
animations: "disabled",
|
||||||
clip: { x: 0, y: 0, width: 10, height: 10 },
|
clip: { x: 0, y: 0, width: 10, height: 10 },
|
||||||
@ -205,11 +205,11 @@ test('should not fail when racing with navigation', async ({ runInlineTest }, te
|
|||||||
test('should successfully screenshot a page with infinite animation with disableAnimation: true', async ({ runInlineTest }, testInfo) => {
|
test('should successfully screenshot a page with infinite animation with disableAnimation: true', async ({ runInlineTest }, testInfo) => {
|
||||||
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await page.goto('${infiniteAnimationURL}');
|
await page.goto('${infiniteAnimationURL}');
|
||||||
await expect(page)._toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
animations: "disabled",
|
animations: "disabled",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -221,11 +221,11 @@ test('should successfully screenshot a page with infinite animation with disable
|
|||||||
|
|
||||||
test('should support clip option for page', async ({ runInlineTest }, testInfo) => {
|
test('should support clip option for page', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': createImage(50, 50, 255, 255, 255),
|
'__screenshots__/a.spec.js/snapshot.png': createImage(50, 50, 255, 255, 255),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
name: 'snapshot.png',
|
name: 'snapshot.png',
|
||||||
clip: { x: 0, y: 0, width: 50, height: 50, },
|
clip: { x: 0, y: 0, width: 50, height: 50, },
|
||||||
});
|
});
|
||||||
@ -237,14 +237,14 @@ test('should support clip option for page', async ({ runInlineTest }, testInfo)
|
|||||||
|
|
||||||
test('should support omitBackground option for locator', async ({ runInlineTest }, testInfo) => {
|
test('should support omitBackground option for locator', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
document.body.style.setProperty('width', '100px');
|
document.body.style.setProperty('width', '100px');
|
||||||
document.body.style.setProperty('height', '100px');
|
document.body.style.setProperty('height', '100px');
|
||||||
});
|
});
|
||||||
await expect(page.locator('body'))._toHaveScreenshot({
|
await expect(page.locator('body')).toHaveScreenshot({
|
||||||
name: 'snapshot.png',
|
name: 'snapshot.png',
|
||||||
omitBackground: true,
|
omitBackground: true,
|
||||||
});
|
});
|
||||||
@ -267,10 +267,10 @@ test('should fail to screenshot an element with infinite animation', async ({ ru
|
|||||||
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
projects: [{
|
projects: [{
|
||||||
expect: {
|
expect: {
|
||||||
_toHaveScreenshot: {
|
toHaveScreenshot: {
|
||||||
animations: 'allow',
|
animations: 'allow',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -279,7 +279,7 @@ test('should fail to screenshot an element with infinite animation', async ({ ru
|
|||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await page.goto('${infiniteAnimationURL}');
|
await page.goto('${infiniteAnimationURL}');
|
||||||
await expect(page.locator('body'))._toHaveScreenshot({ timeout: 2000 });
|
await expect(page.locator('body')).toHaveScreenshot({ timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -297,9 +297,9 @@ test('should fail to screenshot an element that keeps moving', async ({ runInlin
|
|||||||
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
expect: {
|
expect: {
|
||||||
_toHaveScreenshot: {
|
toHaveScreenshot: {
|
||||||
animations: 'allow',
|
animations: 'allow',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -307,7 +307,7 @@ test('should fail to screenshot an element that keeps moving', async ({ runInlin
|
|||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await page.goto('${infiniteAnimationURL}');
|
await page.goto('${infiniteAnimationURL}');
|
||||||
await expect(page.locator('div'))._toHaveScreenshot({ timeout: 2000 });
|
await expect(page.locator('div')).toHaveScreenshot({ timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -322,10 +322,10 @@ test('should fail to screenshot an element that keeps moving', async ({ runInlin
|
|||||||
|
|
||||||
test('should generate default name', async ({ runInlineTest }, testInfo) => {
|
test('should generate default name', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot();
|
await expect(page).toHaveScreenshot();
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -335,10 +335,11 @@ test('should generate default name', async ({ runInlineTest }, testInfo) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should compile with different option combinations', async ({ runTSC }) => {
|
test('should compile with different option combinations', async ({ runTSC }) => {
|
||||||
test.skip(true, 'Enable when enabling _toHaveScreenshot');
|
const experimentalPath = path.resolve(__dirname, '..', 'config', 'experimental.d.ts');
|
||||||
|
|
||||||
const result = await runTSC({
|
const result = await runTSC({
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
|
//@no-header
|
||||||
|
/// <reference path=${JSON.stringify(experimentalPath)} />
|
||||||
import type { PlaywrightTestConfig } from '@playwright/test';
|
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||||
const config: PlaywrightTestConfig = {
|
const config: PlaywrightTestConfig = {
|
||||||
expect: {
|
expect: {
|
||||||
@ -360,7 +361,7 @@ test('should compile with different option combinations', async ({ runTSC }) =>
|
|||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
test('is a test', async ({ page }) => {
|
test('is a test', async ({ page }) => {
|
||||||
await expect(page).toHaveScreenshot();
|
await expect(page).toHaveScreenshot();
|
||||||
await expect(page.locator('body'))._toHaveScreenshot({ threshold: 0.2 });
|
await expect(page.locator('body')).toHaveScreenshot({ threshold: 0.2 });
|
||||||
await expect(page).toHaveScreenshot({ maxDiffPixelRatio: 0.2 });
|
await expect(page).toHaveScreenshot({ maxDiffPixelRatio: 0.2 });
|
||||||
await expect(page).toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
threshold: 0.2,
|
threshold: 0.2,
|
||||||
@ -381,11 +382,11 @@ test('should compile with different option combinations', async ({ runTSC }) =>
|
|||||||
|
|
||||||
test('should fail when screenshot is different size', async ({ runInlineTest }) => {
|
test('should fail when screenshot is different size', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': createImage(22, 33),
|
'__screenshots__/a.spec.js/snapshot.png': createImage(22, 33),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -400,7 +401,7 @@ test('should fail when given non-png snapshot name', async ({ runInlineTest }) =
|
|||||||
...playwrightConfig({}),
|
...playwrightConfig({}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.jpeg');
|
await expect(page).toHaveScreenshot('snapshot.jpeg');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -413,7 +414,7 @@ test('should fail when given buffer', async ({ runInlineTest }) => {
|
|||||||
...playwrightConfig({}),
|
...playwrightConfig({}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(Buffer.from([1]))._toHaveScreenshot();
|
await expect(Buffer.from([1])).toHaveScreenshot();
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -423,11 +424,11 @@ test('should fail when given buffer', async ({ runInlineTest }) => {
|
|||||||
|
|
||||||
test('should fail when screenshot is different pixels', async ({ runInlineTest }) => {
|
test('should fail when screenshot is different pixels', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': paintBlackPixels(whiteImage, 12345),
|
'__screenshots__/a.spec.js/snapshot.png': paintBlackPixels(whiteImage, 12345),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -442,11 +443,11 @@ test('should fail when screenshot is different pixels', async ({ runInlineTest }
|
|||||||
|
|
||||||
test('doesn\'t create comparison artifacts in an output folder for passed negated snapshot matcher', async ({ runInlineTest }, testInfo) => {
|
test('doesn\'t create comparison artifacts in an output folder for passed negated snapshot matcher', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': blueImage,
|
'__screenshots__/a.spec.js/snapshot.png': blueImage,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page).not._toHaveScreenshot('snapshot.png');
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -463,11 +464,11 @@ test('doesn\'t create comparison artifacts in an output folder for passed negate
|
|||||||
|
|
||||||
test('should fail on same snapshots with negate matcher', async ({ runInlineTest }) => {
|
test('should fail on same snapshots with negate matcher', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': whiteImage,
|
'__screenshots__/a.spec.js/snapshot.png': whiteImage,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page).not._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).not.toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -479,11 +480,11 @@ test('should fail on same snapshots with negate matcher', async ({ runInlineTest
|
|||||||
|
|
||||||
test('should write missing expectations locally twice and continue', async ({ runInlineTest }, testInfo) => {
|
test('should write missing expectations locally twice and continue', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
await expect(page)._toHaveScreenshot('snapshot2.png');
|
await expect(page).toHaveScreenshot('snapshot2.png');
|
||||||
console.log('Here we are!');
|
console.log('Here we are!');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
@ -509,10 +510,10 @@ test('should write missing expectations locally twice and continue', async ({ ru
|
|||||||
|
|
||||||
test('shouldn\'t write missing expectations locally for negated matcher', async ({ runInlineTest }, testInfo) => {
|
test('shouldn\'t write missing expectations locally for negated matcher', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page).not._toHaveScreenshot('snapshot.png');
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -525,11 +526,11 @@ test('shouldn\'t write missing expectations locally for negated matcher', async
|
|||||||
|
|
||||||
test('should update snapshot with the update-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
test('should update snapshot with the update-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': blueImage,
|
'__screenshots__/a.spec.js/snapshot.png': blueImage,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -543,11 +544,11 @@ test('should update snapshot with the update-snapshots flag', async ({ runInline
|
|||||||
test('shouldn\'t update snapshot with the update-snapshots flag for negated matcher', async ({ runInlineTest }, testInfo) => {
|
test('shouldn\'t update snapshot with the update-snapshots flag for negated matcher', async ({ runInlineTest }, testInfo) => {
|
||||||
const EXPECTED_SNAPSHOT = blueImage;
|
const EXPECTED_SNAPSHOT = blueImage;
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page).not._toHaveScreenshot('snapshot.png');
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -559,10 +560,10 @@ test('shouldn\'t update snapshot with the update-snapshots flag for negated matc
|
|||||||
|
|
||||||
test('should silently write missing expectations locally with the update-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
test('should silently write missing expectations locally with the update-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -576,10 +577,10 @@ test('should silently write missing expectations locally with the update-snapsho
|
|||||||
|
|
||||||
test('should not write missing expectations locally with the update-snapshots flag for negated matcher', async ({ runInlineTest }, testInfo) => {
|
test('should not write missing expectations locally with the update-snapshots flag for negated matcher', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page).not._toHaveScreenshot('snapshot.png');
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -592,7 +593,7 @@ test('should not write missing expectations locally with the update-snapshots fl
|
|||||||
|
|
||||||
test('should match multiple snapshots', async ({ runInlineTest }) => {
|
test('should match multiple snapshots', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/red.png': redImage,
|
'__screenshots__/a.spec.js/red.png': redImage,
|
||||||
'__screenshots__/a.spec.js/green.png': greenImage,
|
'__screenshots__/a.spec.js/green.png': greenImage,
|
||||||
'__screenshots__/a.spec.js/blue.png': blueImage,
|
'__screenshots__/a.spec.js/blue.png': blueImage,
|
||||||
@ -600,15 +601,15 @@ test('should match multiple snapshots', async ({ runInlineTest }) => {
|
|||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.evaluate(() => document.documentElement.style.setProperty('background', '#f00')),
|
page.evaluate(() => document.documentElement.style.setProperty('background', '#f00')),
|
||||||
expect(page)._toHaveScreenshot('red.png'),
|
expect(page).toHaveScreenshot('red.png'),
|
||||||
]);
|
]);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.evaluate(() => document.documentElement.style.setProperty('background', '#0f0')),
|
page.evaluate(() => document.documentElement.style.setProperty('background', '#0f0')),
|
||||||
expect(page)._toHaveScreenshot('green.png'),
|
expect(page).toHaveScreenshot('green.png'),
|
||||||
]);
|
]);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.evaluate(() => document.documentElement.style.setProperty('background', '#00f')),
|
page.evaluate(() => document.documentElement.style.setProperty('background', '#00f')),
|
||||||
expect(page)._toHaveScreenshot('blue.png'),
|
expect(page).toHaveScreenshot('blue.png'),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
@ -618,11 +619,11 @@ test('should match multiple snapshots', async ({ runInlineTest }) => {
|
|||||||
|
|
||||||
test('should use provided name', async ({ runInlineTest }) => {
|
test('should use provided name', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/provided.png': whiteImage,
|
'__screenshots__/a.spec.js/provided.png': whiteImage,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('provided.png');
|
await expect(page).toHaveScreenshot('provided.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -631,11 +632,11 @@ test('should use provided name', async ({ runInlineTest }) => {
|
|||||||
|
|
||||||
test('should use provided name via options', async ({ runInlineTest }) => {
|
test('should use provided name via options', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/provided.png': whiteImage,
|
'__screenshots__/a.spec.js/provided.png': whiteImage,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot({ name: 'provided.png' });
|
await expect(page).toHaveScreenshot({ name: 'provided.png' });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -647,21 +648,21 @@ test('should respect maxDiffPixels option', async ({ runInlineTest }) => {
|
|||||||
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
})).exitCode, 'make sure default comparison fails').toBe(1);
|
})).exitCode, 'make sure default comparison fails').toBe(1);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', {
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
||||||
maxDiffPixels: ${BAD_PIXELS}
|
maxDiffPixels: ${BAD_PIXELS}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -672,9 +673,9 @@ test('should respect maxDiffPixels option', async ({ runInlineTest }) => {
|
|||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
expect: {
|
expect: {
|
||||||
_toHaveScreenshot: {
|
toHaveScreenshot: {
|
||||||
maxDiffPixels: BAD_PIXELS
|
maxDiffPixels: BAD_PIXELS
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -684,7 +685,7 @@ test('should respect maxDiffPixels option', async ({ runInlineTest }) => {
|
|||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
})).exitCode, 'make sure maxDiffPixels option in project config is respected').toBe(0);
|
})).exitCode, 'make sure maxDiffPixels option in project config is respected').toBe(0);
|
||||||
@ -696,21 +697,21 @@ test('should satisfy both maxDiffPixelRatio and maxDiffPixels', async ({ runInli
|
|||||||
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_COUNT);
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_COUNT);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
})).exitCode, 'make sure default comparison fails').toBe(1);
|
})).exitCode, 'make sure default comparison fails').toBe(1);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', {
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
||||||
maxDiffPixels: ${Math.floor(BAD_COUNT / 2)},
|
maxDiffPixels: ${Math.floor(BAD_COUNT / 2)},
|
||||||
maxDiffPixelRatio: ${BAD_RATIO},
|
maxDiffPixelRatio: ${BAD_RATIO},
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
@ -720,11 +721,11 @@ test('should satisfy both maxDiffPixelRatio and maxDiffPixels', async ({ runInli
|
|||||||
})).exitCode, 'make sure it fails when maxDiffPixels < actualBadPixels < maxDiffPixelRatio').toBe(1);
|
})).exitCode, 'make sure it fails when maxDiffPixels < actualBadPixels < maxDiffPixelRatio').toBe(1);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', {
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
||||||
maxDiffPixels: ${BAD_COUNT},
|
maxDiffPixels: ${BAD_COUNT},
|
||||||
maxDiffPixelRatio: ${BAD_RATIO / 2},
|
maxDiffPixelRatio: ${BAD_RATIO / 2},
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
@ -734,11 +735,11 @@ test('should satisfy both maxDiffPixelRatio and maxDiffPixels', async ({ runInli
|
|||||||
})).exitCode, 'make sure it fails when maxDiffPixelRatio < actualBadPixels < maxDiffPixels').toBe(1);
|
})).exitCode, 'make sure it fails when maxDiffPixelRatio < actualBadPixels < maxDiffPixels').toBe(1);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', {
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
||||||
maxDiffPixels: ${BAD_COUNT},
|
maxDiffPixels: ${BAD_COUNT},
|
||||||
maxDiffPixelRatio: ${BAD_RATIO},
|
maxDiffPixelRatio: ${BAD_RATIO},
|
||||||
});
|
});
|
||||||
@ -753,21 +754,21 @@ test('should respect maxDiffPixelRatio option', async ({ runInlineTest }) => {
|
|||||||
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
})).exitCode, 'make sure default comparison fails').toBe(1);
|
})).exitCode, 'make sure default comparison fails').toBe(1);
|
||||||
|
|
||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', {
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
||||||
maxDiffPixelRatio: ${BAD_RATIO}
|
maxDiffPixelRatio: ${BAD_RATIO}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -777,9 +778,9 @@ test('should respect maxDiffPixelRatio option', async ({ runInlineTest }) => {
|
|||||||
expect((await runInlineTest({
|
expect((await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
projects: [{
|
projects: [{
|
||||||
_screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
expect: {
|
expect: {
|
||||||
_toHaveScreenshot: {
|
toHaveScreenshot: {
|
||||||
maxDiffPixelRatio: BAD_RATIO,
|
maxDiffPixelRatio: BAD_RATIO,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -788,7 +789,7 @@ test('should respect maxDiffPixelRatio option', async ({ runInlineTest }) => {
|
|||||||
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
})).exitCode, 'make sure maxDiffPixels option in project config is respected').toBe(0);
|
})).exitCode, 'make sure maxDiffPixels option in project config is respected').toBe(0);
|
||||||
@ -799,7 +800,7 @@ test('should throw for invalid maxDiffPixels values', async ({ runInlineTest })
|
|||||||
...playwrightConfig({}),
|
...playwrightConfig({}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
maxDiffPixels: -1,
|
maxDiffPixels: -1,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -812,7 +813,7 @@ test('should throw for invalid maxDiffPixelRatio values', async ({ runInlineTest
|
|||||||
...playwrightConfig({}),
|
...playwrightConfig({}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot({
|
await expect(page).toHaveScreenshot({
|
||||||
maxDiffPixelRatio: 12,
|
maxDiffPixelRatio: 12,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -823,14 +824,14 @@ test('should throw for invalid maxDiffPixelRatio values', async ({ runInlineTest
|
|||||||
|
|
||||||
test('should attach expected/actual and no diff when sizes are different', async ({ runInlineTest }, testInfo) => {
|
test('should attach expected/actual and no diff when sizes are different', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({ _screenshotsDir: '__screenshots__' }),
|
...playwrightConfig({ screenshotsDir: '__screenshots__' }),
|
||||||
'__screenshots__/a.spec.js/snapshot.png': createImage(2, 2),
|
'__screenshots__/a.spec.js/snapshot.png': createImage(2, 2),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test.afterEach(async ({}, testInfo) => {
|
pwt.test.afterEach(async ({}, testInfo) => {
|
||||||
console.log('## ' + JSON.stringify(testInfo.attachments));
|
console.log('## ' + JSON.stringify(testInfo.attachments));
|
||||||
});
|
});
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -859,11 +860,11 @@ test('should fail with missing expectations and retries', async ({ runInlineTest
|
|||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
retries: 1,
|
retries: 1,
|
||||||
_screenshotsDir: '__screenshots__'
|
screenshotsDir: '__screenshots__'
|
||||||
}),
|
}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
@ -880,11 +881,11 @@ test('should update expectations with retries', async ({ runInlineTest }, testIn
|
|||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
...playwrightConfig({
|
...playwrightConfig({
|
||||||
retries: 1,
|
retries: 1,
|
||||||
_screenshotsDir: '__screenshots__'
|
screenshotsDir: '__screenshots__'
|
||||||
}),
|
}),
|
||||||
'a.spec.js': `
|
'a.spec.js': `
|
||||||
pwt.test('is a test', async ({ page }) => {
|
pwt.test('is a test', async ({ page }) => {
|
||||||
await expect(page)._toHaveScreenshot('snapshot.png');
|
await expect(page).toHaveScreenshot('snapshot.png');
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
}, { 'update-snapshots': true });
|
}, { 'update-snapshots': true });
|
||||||
@ -900,6 +901,7 @@ test('should update expectations with retries', async ({ runInlineTest }, testIn
|
|||||||
function playwrightConfig(obj: any) {
|
function playwrightConfig(obj: any) {
|
||||||
return {
|
return {
|
||||||
'playwright.config.js': `
|
'playwright.config.js': `
|
||||||
|
process.env.PLAYWRIGHT_EXPERIMENTAL_FEATURES = '1';
|
||||||
module.exports = ${JSON.stringify(obj, null, 2)}
|
module.exports = ${JSON.stringify(obj, null, 2)}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -91,7 +91,7 @@ class ApiParser {
|
|||||||
let optional = false;
|
let optional = false;
|
||||||
for (const item of spec.children || []) {
|
for (const item of spec.children || []) {
|
||||||
if (item.type === 'li' && item.liType === 'default') {
|
if (item.type === 'li' && item.liType === 'default') {
|
||||||
const parsed = this.parseType(item);;
|
const parsed = this.parseType(item);
|
||||||
returnType = parsed.type;
|
returnType = parsed.type;
|
||||||
optional = parsed.optional;
|
optional = parsed.optional;
|
||||||
}
|
}
|
||||||
@ -164,6 +164,7 @@ class ApiParser {
|
|||||||
method.argsArray.push(arg);
|
method.argsArray.push(arg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// match[1] === 'option'
|
||||||
let options = method.argsArray.find(o => o.name === 'options');
|
let options = method.argsArray.find(o => o.name === 'options');
|
||||||
if (!options) {
|
if (!options) {
|
||||||
const type = new Documentation.Type('Object', []);
|
const type = new Documentation.Type('Object', []);
|
||||||
@ -183,7 +184,7 @@ class ApiParser {
|
|||||||
const param = childrenWithoutProperties(spec)[0];
|
const param = childrenWithoutProperties(spec)[0];
|
||||||
const text = param.text;
|
const text = param.text;
|
||||||
let typeStart = text.indexOf('<');
|
let typeStart = text.indexOf('<');
|
||||||
if (text[typeStart - 1] === '?')
|
while ('?e'.includes(text[typeStart - 1]))
|
||||||
typeStart--;
|
typeStart--;
|
||||||
const name = text.substring(0, typeStart).replace(/\`/g, '').trim();
|
const name = text.substring(0, typeStart).replace(/\`/g, '').trim();
|
||||||
const comments = extractComments(spec);
|
const comments = extractComments(spec);
|
||||||
@ -193,7 +194,7 @@ class ApiParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MarkdownNode=} spec
|
* @param {MarkdownNode=} spec
|
||||||
* @return {{ type: Documentation.Type, optional: boolean }}
|
* @return {{ type: Documentation.Type, optional: boolean, experimental: boolean }}
|
||||||
*/
|
*/
|
||||||
parseType(spec) {
|
parseType(spec) {
|
||||||
const arg = parseVariable(spec.text);
|
const arg = parseVariable(spec.text);
|
||||||
@ -202,16 +203,16 @@ class ApiParser {
|
|||||||
const { name, text } = parseVariable(child.text);
|
const { name, text } = parseVariable(child.text);
|
||||||
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
|
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
|
||||||
const childType = this.parseType(child);
|
const childType = this.parseType(child);
|
||||||
properties.push(Documentation.Member.createProperty({}, false /* experimental */, name, childType.type, comments, !childType.optional));
|
properties.push(Documentation.Member.createProperty({}, childType.experimental, name, childType.type, comments, !childType.optional));
|
||||||
}
|
}
|
||||||
const type = Documentation.Type.parse(arg.type, properties);
|
const type = Documentation.Type.parse(arg.type, properties);
|
||||||
return { type, optional: arg.optional };
|
return { type, optional: arg.optional, experimental: arg.experimental };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} line
|
* @param {string} line
|
||||||
* @returns {{ name: string, type: string, text: string, optional: boolean }}
|
* @returns {{ name: string, type: string, text: string, optional: boolean, experimental: boolean }}
|
||||||
*/
|
*/
|
||||||
function parseVariable(line) {
|
function parseVariable(line) {
|
||||||
let match = line.match(/^`([^`]+)` (.*)/);
|
let match = line.match(/^`([^`]+)` (.*)/);
|
||||||
@ -226,8 +227,12 @@ function parseVariable(line) {
|
|||||||
const name = match[1];
|
const name = match[1];
|
||||||
let remainder = match[2];
|
let remainder = match[2];
|
||||||
let optional = false;
|
let optional = false;
|
||||||
if (remainder.startsWith('?')) {
|
let experimental = false;
|
||||||
|
while ('?e'.includes(remainder[0])) {
|
||||||
|
if (remainder[0] === '?')
|
||||||
optional = true;
|
optional = true;
|
||||||
|
else if (remainder[0] === 'e')
|
||||||
|
experimental = true;
|
||||||
remainder = remainder.substring(1);
|
remainder = remainder.substring(1);
|
||||||
}
|
}
|
||||||
if (!remainder.startsWith('<'))
|
if (!remainder.startsWith('<'))
|
||||||
@ -240,7 +245,7 @@ function parseVariable(line) {
|
|||||||
if (c === '>')
|
if (c === '>')
|
||||||
--depth;
|
--depth;
|
||||||
if (depth === 0)
|
if (depth === 0)
|
||||||
return { name, type: remainder.substring(1, i), text: remainder.substring(i + 2), optional };
|
return { name, type: remainder.substring(1, i), text: remainder.substring(i + 2), optional, experimental };
|
||||||
}
|
}
|
||||||
throw new Error('Should not be reached');
|
throw new Error('Should not be reached');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,10 +32,10 @@ class TypesGenerator {
|
|||||||
/**
|
/**
|
||||||
* @param {{
|
* @param {{
|
||||||
* documentation: Documentation,
|
* documentation: Documentation,
|
||||||
* classNamesToGenerate: Set<string>,
|
|
||||||
* overridesToDocsClassMapping?: Map<string, string>,
|
* overridesToDocsClassMapping?: Map<string, string>,
|
||||||
* ignoreMissing?: Set<string>,
|
* ignoreMissing?: Set<string>,
|
||||||
* doNotExportClassNames?: Set<string>,
|
* doNotExportClassNames?: Set<string>,
|
||||||
|
* doNotGenerate?: Set<string>,
|
||||||
* includeExperimental?: boolean,
|
* includeExperimental?: boolean,
|
||||||
* }} options
|
* }} options
|
||||||
*/
|
*/
|
||||||
@ -45,10 +45,10 @@ class TypesGenerator {
|
|||||||
/** @type {Set<string>} */
|
/** @type {Set<string>} */
|
||||||
this.handledMethods = new Set();
|
this.handledMethods = new Set();
|
||||||
this.documentation = options.documentation;
|
this.documentation = options.documentation;
|
||||||
this.classNamesToGenerate = options.classNamesToGenerate;
|
|
||||||
this.overridesToDocsClassMapping = options.overridesToDocsClassMapping || new Map();
|
this.overridesToDocsClassMapping = options.overridesToDocsClassMapping || new Map();
|
||||||
this.ignoreMissing = options.ignoreMissing || new Set();
|
this.ignoreMissing = options.ignoreMissing || new Set();
|
||||||
this.doNotExportClassNames = options.doNotExportClassNames || new Set();
|
this.doNotExportClassNames = options.doNotExportClassNames || new Set();
|
||||||
|
this.doNotGenerate = options.doNotGenerate || new Set();
|
||||||
this.documentation.filterForLanguage('js');
|
this.documentation.filterForLanguage('js');
|
||||||
if (!options.includeExperimental)
|
if (!options.includeExperimental)
|
||||||
this.documentation.filterOutExperimental();
|
this.documentation.filterOutExperimental();
|
||||||
@ -116,13 +116,15 @@ class TypesGenerator {
|
|||||||
return this.memberJSDOC(method, ' ').trimLeft();
|
return this.memberJSDOC(method, ' ').trimLeft();
|
||||||
}, (className) => {
|
}, (className) => {
|
||||||
const docClass = this.docClassForName(className);
|
const docClass = this.docClassForName(className);
|
||||||
if (!docClass || !this.classNamesToGenerate.has(docClass.name))
|
if (!docClass || !this.shouldGenerate(docClass.name))
|
||||||
|
return '';
|
||||||
|
if (docClass.name !== className) // Do not generate members for name-mapped classes.
|
||||||
return '';
|
return '';
|
||||||
return this.classBody(docClass);
|
return this.classBody(docClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
const classes = this.documentation.classesArray
|
const classes = this.documentation.classesArray
|
||||||
.filter(cls => this.classNamesToGenerate.has(cls.name))
|
.filter(cls => this.shouldGenerate(cls.name))
|
||||||
.filter(cls => !handledClasses.has(cls.name));
|
.filter(cls => !handledClasses.has(cls.name));
|
||||||
{
|
{
|
||||||
const playwright = this.documentation.classesArray.find(c => c.name === 'Playwright');
|
const playwright = this.documentation.classesArray.find(c => c.name === 'Playwright');
|
||||||
@ -151,6 +153,16 @@ class TypesGenerator {
|
|||||||
return this.ignoreMissing.has(name) || this.ignoreMissing.has(parts[0]);
|
return this.ignoreMissing.has(name) || this.ignoreMissing.has(parts[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
*/
|
||||||
|
shouldGenerate(name) {
|
||||||
|
const parts = name.split('.');
|
||||||
|
// Either the class is skipped, or a specific method.
|
||||||
|
const skip = this.doNotGenerate.has(name) || this.doNotGenerate.has(parts[0]);
|
||||||
|
return !skip;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
*/
|
*/
|
||||||
@ -269,6 +281,8 @@ class TypesGenerator {
|
|||||||
|
|
||||||
const members = classDesc.membersArray.filter(member => member.kind !== 'event');
|
const members = classDesc.membersArray.filter(member => member.kind !== 'event');
|
||||||
parts.push(members.map(member => {
|
parts.push(members.map(member => {
|
||||||
|
if (!this.shouldGenerate(`${classDesc.name}.${member.name}`))
|
||||||
|
return '';
|
||||||
if (member.kind === 'event')
|
if (member.kind === 'event')
|
||||||
return '';
|
return '';
|
||||||
if (member.alias === 'waitForEvent') {
|
if (member.alias === 'waitForEvent') {
|
||||||
@ -490,7 +504,7 @@ class TypesGenerator {
|
|||||||
const coreDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
|
const coreDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
|
||||||
const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
|
const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
|
||||||
const reporterDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api'));
|
const reporterDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api'));
|
||||||
const assertionClasses = new Set(['LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'ScreenshotAssertions']);
|
const assertionClasses = new Set(['LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'ScreenshotAssertions', 'PlaywrightAssertions']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {boolean} includeExperimental
|
* @param {boolean} includeExperimental
|
||||||
@ -500,7 +514,7 @@ class TypesGenerator {
|
|||||||
const documentation = coreDocumentation.clone();
|
const documentation = coreDocumentation.clone();
|
||||||
const generator = new TypesGenerator({
|
const generator = new TypesGenerator({
|
||||||
documentation,
|
documentation,
|
||||||
classNamesToGenerate: new Set(coreDocumentation.classesArray.map(cls => cls.name).filter(name => !assertionClasses.has(name) && name !== 'PlaywrightAssertions')),
|
doNotGenerate: new Set([...assertionClasses]),
|
||||||
includeExperimental,
|
includeExperimental,
|
||||||
});
|
});
|
||||||
let types = await generator.generateTypes(path.join(__dirname, 'overrides.d.ts'));
|
let types = await generator.generateTypes(path.join(__dirname, 'overrides.d.ts'));
|
||||||
@ -531,7 +545,15 @@ class TypesGenerator {
|
|||||||
const documentation = coreDocumentation.mergeWith(testDocumentation);
|
const documentation = coreDocumentation.mergeWith(testDocumentation);
|
||||||
const generator = new TypesGenerator({
|
const generator = new TypesGenerator({
|
||||||
documentation,
|
documentation,
|
||||||
classNamesToGenerate: new Set(['TestError', 'TestInfo', 'WorkerInfo', ...assertionClasses]),
|
doNotGenerate: new Set([
|
||||||
|
...coreDocumentation.classesArray.map(cls => cls.name).filter(name => !assertionClasses.has(name)),
|
||||||
|
'PlaywrightAssertions',
|
||||||
|
'Test',
|
||||||
|
'Fixtures',
|
||||||
|
'TestOptions',
|
||||||
|
'TestConfig.use',
|
||||||
|
'TestProject.use',
|
||||||
|
]),
|
||||||
overridesToDocsClassMapping: new Map([
|
overridesToDocsClassMapping: new Map([
|
||||||
['TestType', 'Test'],
|
['TestType', 'Test'],
|
||||||
['Config', 'TestConfig'],
|
['Config', 'TestConfig'],
|
||||||
@ -565,7 +587,10 @@ class TypesGenerator {
|
|||||||
const documentation = coreDocumentation.mergeWith(testDocumentation).mergeWith(reporterDocumentation);
|
const documentation = coreDocumentation.mergeWith(testDocumentation).mergeWith(reporterDocumentation);
|
||||||
const generator = new TypesGenerator({
|
const generator = new TypesGenerator({
|
||||||
documentation,
|
documentation,
|
||||||
classNamesToGenerate: new Set(reporterDocumentation.classesArray.map(cls => cls.name)),
|
doNotGenerate: new Set([
|
||||||
|
...coreDocumentation.classesArray.map(cls => cls.name),
|
||||||
|
...testDocumentation.classesArray.map(cls => cls.name),
|
||||||
|
]),
|
||||||
ignoreMissing: new Set(['FullResult']),
|
ignoreMissing: new Set(['FullResult']),
|
||||||
includeExperimental,
|
includeExperimental,
|
||||||
});
|
});
|
||||||
|
|||||||
22
utils/generate_types/overrides-test.d.ts
vendored
22
utils/generate_types/overrides-test.d.ts
vendored
@ -35,28 +35,7 @@ export type UpdateSnapshots = 'all' | 'none' | 'missing';
|
|||||||
|
|
||||||
type UseOptions<TestArgs, WorkerArgs> = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] };
|
type UseOptions<TestArgs, WorkerArgs> = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] };
|
||||||
|
|
||||||
type ExpectSettings = {
|
|
||||||
/**
|
|
||||||
* Default timeout for async expect matchers in milliseconds, defaults to 5000ms.
|
|
||||||
*/
|
|
||||||
timeout?: number;
|
|
||||||
toMatchSnapshot?: {
|
|
||||||
/** An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between pixels in compared images, between zero (strict) and one (lax). Defaults to `0.2`.
|
|
||||||
*/
|
|
||||||
threshold?: number,
|
|
||||||
/**
|
|
||||||
* An acceptable amount of pixels that could be different, unset by default.
|
|
||||||
*/
|
|
||||||
maxDiffPixels?: number,
|
|
||||||
/**
|
|
||||||
* An acceptable ratio of pixels that are different to the total amount of pixels, between `0` and `1` , unset by default.
|
|
||||||
*/
|
|
||||||
maxDiffPixelRatio?: number,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interface TestProject {
|
interface TestProject {
|
||||||
expect?: ExpectSettings;
|
|
||||||
fullyParallel?: boolean;
|
fullyParallel?: boolean;
|
||||||
grep?: RegExp | RegExp[];
|
grep?: RegExp | RegExp[];
|
||||||
grepInvert?: RegExp | RegExp[] | null;
|
grepInvert?: RegExp | RegExp[] | null;
|
||||||
@ -139,7 +118,6 @@ interface TestConfig {
|
|||||||
webServer?: WebServerConfig;
|
webServer?: WebServerConfig;
|
||||||
workers?: number;
|
workers?: number;
|
||||||
|
|
||||||
expect?: ExpectSettings;
|
|
||||||
metadata?: any;
|
metadata?: any;
|
||||||
name?: string;
|
name?: string;
|
||||||
snapshotDir?: string;
|
snapshotDir?: string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user