chore: simplify types handling in toHaveScreenshot (#29374)

This commit is contained in:
Pavel Feldman 2024-02-05 19:07:30 -08:00 committed by GitHub
parent fb29d90052
commit 20699c36ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 164 additions and 195 deletions

View file

@ -62,14 +62,13 @@ type PDFOptions = Omit<channels.PagePdfParams, 'width' | 'height' | 'margin'> &
path?: string,
};
type ExpectScreenshotOptions = Omit<channels.PageExpectScreenshotOptions, 'screenshotOptions' | 'locator' | 'expected'> & {
export type ExpectScreenshotOptions = Omit<channels.PageExpectScreenshotOptions, 'locator' | 'expected' | 'mask'> & {
expected?: Buffer,
locator?: Locator,
locator?: api.Locator,
isNot: boolean,
screenshotOptions: Omit<channels.PageExpectScreenshotOptions['screenshotOptions'], 'mask'> & { mask?: Locator[] }
mask?: api.Locator[],
};
export class Page extends ChannelOwner<channels.PageChannel> implements api.Page {
private _browserContext: BrowserContext;
_ownedContext: BrowserContext | undefined;
@ -547,22 +546,19 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}
async _expectScreenshot(options: ExpectScreenshotOptions): Promise<{ actual?: Buffer, previous?: Buffer, diff?: Buffer, errorMessage?: string, log?: string[]}> {
const mask = options.screenshotOptions?.mask ? options.screenshotOptions?.mask.map(locator => ({
frame: locator._frame._channel,
selector: locator._selector,
const mask = options?.mask ? options?.mask.map(locator => ({
frame: (locator as Locator)._frame._channel,
selector: (locator as Locator)._selector,
})) : undefined;
const locator = options.locator ? {
frame: options.locator._frame._channel,
selector: options.locator._selector,
frame: (options.locator as Locator)._frame._channel,
selector: (options.locator as Locator)._selector,
} : undefined;
return await this._channel.expectScreenshot({
...options,
isNot: !!options.isNot,
locator,
screenshotOptions: {
...options.screenshotOptions,
mask,
}
mask,
});
}

View file

@ -1059,26 +1059,22 @@ scheme.PageExpectScreenshotParams = tObject({
frame: tChannel(['Frame']),
selector: tString,
})),
comparatorOptions: tOptional(tObject({
comparator: tOptional(tString),
maxDiffPixels: tOptional(tNumber),
maxDiffPixelRatio: tOptional(tNumber),
threshold: tOptional(tNumber),
})),
screenshotOptions: tOptional(tObject({
fullPage: tOptional(tBoolean),
clip: tOptional(tType('Rect')),
omitBackground: tOptional(tBoolean),
caret: tOptional(tEnum(['hide', 'initial'])),
animations: tOptional(tEnum(['disabled', 'allow'])),
scale: tOptional(tEnum(['css', 'device'])),
mask: tOptional(tArray(tObject({
frame: tChannel(['Frame']),
selector: tString,
}))),
maskColor: tOptional(tString),
style: tOptional(tString),
})),
comparator: tOptional(tString),
maxDiffPixels: tOptional(tNumber),
maxDiffPixelRatio: tOptional(tNumber),
threshold: tOptional(tNumber),
fullPage: tOptional(tBoolean),
clip: tOptional(tType('Rect')),
omitBackground: tOptional(tBoolean),
caret: tOptional(tEnum(['hide', 'initial'])),
animations: tOptional(tEnum(['disabled', 'allow'])),
scale: tOptional(tEnum(['css', 'device'])),
mask: tOptional(tArray(tObject({
frame: tChannel(['Frame']),
selector: tString,
}))),
maskColor: tOptional(tString),
style: tOptional(tString),
});
scheme.PageExpectScreenshotResult = tObject({
diff: tOptional(tBinary),

View file

@ -179,7 +179,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
}
async expectScreenshot(params: channels.PageExpectScreenshotParams, metadata: CallMetadata): Promise<channels.PageExpectScreenshotResult> {
const mask: { frame: Frame, selector: string }[] = (params.screenshotOptions?.mask || []).map(({ frame, selector }) => ({
const mask: { frame: Frame, selector: string }[] = (params.mask || []).map(({ frame, selector }) => ({
frame: (frame as FrameDispatcher)._object,
selector,
}));
@ -190,14 +190,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
return await this._page.expectScreenshot(metadata, {
...params,
locator,
comparatorOptions: {
...params.comparatorOptions,
_comparator: params.comparatorOptions?.comparator,
},
screenshotOptions: {
...params.screenshotOptions,
mask,
},
mask,
});
}

View file

@ -110,7 +110,7 @@ type EmulatedMedia = {
forcedColors: types.ForcedColors;
};
type ExpectScreenshotOptions = {
type ExpectScreenshotOptions = ImageComparatorOptions & ScreenshotOptions & {
timeout?: number,
expected?: Buffer,
isNot?: boolean,
@ -118,8 +118,6 @@ type ExpectScreenshotOptions = {
frame: frames.Frame,
selector: string,
},
comparatorOptions?: ImageComparatorOptions,
screenshotOptions?: ScreenshotOptions,
};
export class Page extends SdkObject {
@ -537,11 +535,11 @@ export class Page extends SdkObject {
async expectScreenshot(metadata: CallMetadata, options: ExpectScreenshotOptions = {}): Promise<{ actual?: Buffer, previous?: Buffer, diff?: Buffer, errorMessage?: string, log?: string[] }> {
const locator = options.locator;
const rafrafScreenshot = locator ? async (progress: Progress, timeout: number) => {
return await locator.frame.rafrafTimeoutScreenshotElementWithProgress(progress, locator.selector, timeout, options.screenshotOptions || {});
return await locator.frame.rafrafTimeoutScreenshotElementWithProgress(progress, locator.selector, timeout, options || {});
} : async (progress: Progress, timeout: number) => {
await this.performLocatorHandlersCheckpoint(progress);
await this.mainFrame().rafrafTimeout(timeout);
return await this._screenshotter.screenshotPage(progress, options.screenshotOptions || {});
return await this._screenshotter.screenshotPage(progress, options || {});
};
const comparator = getComparator('image/png');
@ -549,7 +547,7 @@ export class Page extends SdkObject {
if (!options.expected && options.isNot)
return { errorMessage: '"not" matcher requires expected result' };
try {
const format = validateScreenshotOptions(options.screenshotOptions || {});
const format = validateScreenshotOptions(options || {});
if (format !== 'png')
throw new Error('Only PNG screenshots are supported');
} catch (error) {
@ -562,7 +560,7 @@ export class Page extends SdkObject {
diff?: Buffer,
} | undefined = undefined;
const areEqualScreenshots = (actual: Buffer | undefined, expected: Buffer | undefined, previous: Buffer | undefined) => {
const comparatorResult = actual && expected ? comparator(actual, expected, options.comparatorOptions) : undefined;
const comparatorResult = actual && expected ? comparator(actual, expected, options) : undefined;
if (comparatorResult !== undefined && !!comparatorResult === !!options.isNot)
return true;
if (comparatorResult)

View file

@ -21,7 +21,7 @@ import { compare } from '../image_tools/compare';
const { diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL } = require('../third_party/diff_match_patch');
import { PNG } from '../utilsBundle';
export type ImageComparatorOptions = { threshold?: number, maxDiffPixels?: number, maxDiffPixelRatio?: number, _comparator?: string };
export type ImageComparatorOptions = { threshold?: number, maxDiffPixels?: number, maxDiffPixelRatio?: number, comparator?: string };
export type ComparatorResult = { diff?: Buffer; errorMessage: string; } | null;
export type Comparator = (actualBuffer: Buffer | string, expectedBuffer: Buffer, options?: any) => ComparatorResult;
@ -65,18 +65,18 @@ function compareImages(mimeType: string, actualBuffer: Buffer | string, expected
}
const diff = new PNG({ width: size.width, height: size.height });
let count;
if (options._comparator === 'ssim-cie94') {
if (options.comparator === 'ssim-cie94') {
count = compare(expected.data, actual.data, diff.data, size.width, size.height, {
// All ΔE* formulae are originally designed to have the difference of 1.0 stand for a "just noticeable difference" (JND).
// See https://en.wikipedia.org/wiki/Color_difference#CIELAB_%CE%94E*
maxColorDeltaE94: 1.0,
});
} else if ((options._comparator ?? 'pixelmatch') === 'pixelmatch') {
} else if ((options.comparator ?? 'pixelmatch') === 'pixelmatch') {
count = pixelmatch(expected.data, actual.data, diff.data, size.width, size.height, {
threshold: options.threshold ?? 0.2,
});
} else {
throw new Error(`Configuration specifies unknown comparator "${options._comparator}"`);
throw new Error(`Configuration specifies unknown comparator "${options.comparator}"`);
}
const maxDiffPixels1 = options.maxDiffPixels;

View file

@ -15,12 +15,10 @@
*/
import type { Locator, Page } from 'playwright-core';
import type { Page as PageEx } from 'playwright-core/lib/client/page';
import type { Locator as LocatorEx } from 'playwright-core/lib/client/locator';
import type { ExpectScreenshotOptions, Page as PageEx } from 'playwright-core/lib/client/page';
import { currentTestInfo, currentExpectTimeout } from '../common/globals';
import type { ImageComparatorOptions, Comparator } from 'playwright-core/lib/utils';
import { getComparator, sanitizeForFilePath, zones } from 'playwright-core/lib/utils';
import type { PageScreenshotOptions } from 'playwright-core/types/types';
import {
addSuffixToFilePath,
trimLongString, callLogText,
@ -32,6 +30,7 @@ import { mime } from 'playwright-core/lib/utilsBundle';
import type { TestInfoImpl } from '../worker/testInfo';
import type { ExpectMatcherContext } from './expect';
import type { MatcherResult } from './matcherHint';
import type { FullProjectInternal } from '../common/config';
type NameOrSegments = string | string[];
const snapshotNamesSymbol = Symbol('snapshotNames');
@ -43,7 +42,36 @@ type SnapshotNames = {
type ImageMatcherResult = MatcherResult<string, string> & { diff?: string };
class SnapshotHelper<T extends ImageComparatorOptions> {
type ToHaveScreenshotConfigOptions = NonNullable<NonNullable<FullProjectInternal['expect']>['toHaveScreenshot']> & {
_comparator?: string;
};
type ToHaveScreenshotOptions = ToHaveScreenshotConfigOptions & {
clip?: {
x: number;
y: number;
width: number;
height: number;
};
fullPage?: boolean;
mask?: Array<Locator>;
maskColor?: string;
omitBackground?: boolean;
timeout?: number;
};
// Keep in sync with above (begin).
const NonConfigProperties: (keyof ToHaveScreenshotOptions)[] = [
'clip',
'fullPage',
'mask',
'maskColor',
'omitBackground',
'timeout',
];
// Keep in sync with above (end).
class SnapshotHelper {
readonly testInfo: TestInfoImpl;
readonly snapshotName: string;
readonly legacyExpectedPath: string;
@ -54,9 +82,8 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
readonly mimeType: string;
readonly kind: 'Screenshot'|'Snapshot';
readonly updateSnapshots: 'all' | 'none' | 'missing';
readonly comparatorOptions: ImageComparatorOptions;
readonly comparator: Comparator;
readonly allOptions: T;
readonly options: Omit<ToHaveScreenshotOptions, '_comparator'> & { comparator?: string };
readonly matcherName: string;
readonly locator: Locator | undefined;
@ -66,19 +93,18 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
locator: Locator | undefined,
snapshotPathResolver: (...pathSegments: string[]) => string,
anonymousSnapshotExtension: string,
configOptions: ImageComparatorOptions,
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & T,
optOptions: T,
configOptions: ToHaveScreenshotConfigOptions,
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ToHaveScreenshotOptions,
optOptions: ToHaveScreenshotOptions,
) {
let options: T;
let name: NameOrSegments | undefined;
if (Array.isArray(nameOrOptions) || typeof nameOrOptions === 'string') {
name = nameOrOptions;
options = optOptions;
this.options = { ...optOptions };
} else {
name = nameOrOptions.name;
options = { ...nameOrOptions };
delete (options as any).name;
this.options = { ...nameOrOptions };
delete (this.options as any).name;
}
let snapshotNames = (testInfo as any)[snapshotNamesSymbol] as SnapshotNames;
@ -116,15 +142,24 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
}
}
options = {
...configOptions,
...options,
const filteredConfigOptions = { ...configOptions };
for (const prop of NonConfigProperties)
delete (filteredConfigOptions as any)[prop];
this.options = {
...filteredConfigOptions,
...this.options,
};
if (options.maxDiffPixels !== undefined && options.maxDiffPixels < 0)
// While comparator is not a part of the public API, it is translated here.
if ((this.options as any)._comparator) {
this.options.comparator = (this.options as any)._comparator;
delete (this.options as any)._comparator;
}
if (this.options.maxDiffPixels !== undefined && this.options.maxDiffPixels < 0)
throw new Error('`maxDiffPixels` option value must be non-negative integer');
if (options.maxDiffPixelRatio !== undefined && (options.maxDiffPixelRatio < 0 || options.maxDiffPixelRatio > 1))
if (this.options.maxDiffPixelRatio !== undefined && (this.options.maxDiffPixelRatio < 0 || this.options.maxDiffPixelRatio > 1))
throw new Error('`maxDiffPixelRatio` option value must be between 0 and 1');
// sanitizes path if string
@ -145,13 +180,6 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
this.comparator = getComparator(this.mimeType);
this.testInfo = testInfo;
this.allOptions = options;
this.comparatorOptions = {
maxDiffPixels: options.maxDiffPixels,
maxDiffPixelRatio: options.maxDiffPixelRatio,
threshold: options.threshold,
_comparator: options._comparator,
};
this.kind = this.mimeType.startsWith('image/') ? 'Screenshot' : 'Snapshot';
}
@ -284,7 +312,7 @@ export function toMatchSnapshot(
if (this.isNot) {
if (!fs.existsSync(helper.snapshotPath))
return helper.handleMissingNegated();
const isDifferent = !!helper.comparator(received, fs.readFileSync(helper.snapshotPath), helper.comparatorOptions);
const isDifferent = !!helper.comparator(received, fs.readFileSync(helper.snapshotPath), helper.options);
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
}
@ -292,7 +320,7 @@ export function toMatchSnapshot(
return helper.handleMissing(received);
const expected = fs.readFileSync(helper.snapshotPath);
const result = helper.comparator(received, expected, helper.comparatorOptions);
const result = helper.comparator(received, expected, helper.options);
if (!result)
return helper.handleMatching();
@ -306,11 +334,9 @@ export function toMatchSnapshot(
return helper.handleDifferent(received, expected, undefined, result.diff, result.errorMessage, undefined);
}
type HaveScreenshotOptions = ImageComparatorOptions & Omit<PageScreenshotOptions, 'type' | 'quality' | 'path' | 'style'> & { stylePath?: string | string[] };
export function toHaveScreenshotStepTitle(
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & HaveScreenshotOptions = {},
optOptions: HaveScreenshotOptions = {}
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ToHaveScreenshotOptions = {},
optOptions: ToHaveScreenshotOptions = {}
): string {
let name: NameOrSegments | undefined;
if (typeof nameOrOptions === 'object' && !Array.isArray(nameOrOptions))
@ -323,8 +349,8 @@ export function toHaveScreenshotStepTitle(
export async function toHaveScreenshot(
this: ExpectMatcherContext,
pageOrLocator: Page | Locator,
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & HaveScreenshotOptions = {},
optOptions: HaveScreenshotOptions = {}
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & ToHaveScreenshotOptions = {},
optOptions: ToHaveScreenshotOptions = {}
): Promise<MatcherResult<NameOrSegments | { name?: NameOrSegments }, string>> {
const testInfo = currentTestInfo();
if (!testInfo)
@ -334,47 +360,45 @@ export async function toHaveScreenshot(
return { pass: !this.isNot, message: () => '', name: 'toHaveScreenshot', expected: nameOrOptions };
expectTypes(pageOrLocator, ['Page', 'Locator'], 'toHaveScreenshot');
const [page, locator] = pageOrLocator.constructor.name === 'Page' ? [(pageOrLocator as PageEx), undefined] : [(pageOrLocator as Locator).page() as PageEx, pageOrLocator as LocatorEx];
const config = (testInfo._projectInternal.expect as any)?.toHaveScreenshot;
const [page, locator] = pageOrLocator.constructor.name === 'Page' ? [(pageOrLocator as PageEx), undefined] : [(pageOrLocator as Locator).page() as PageEx, pageOrLocator as Locator];
const configOptions = testInfo._projectInternal.expect?.toHaveScreenshot || {};
const snapshotPathResolver = testInfo.snapshotPath.bind(testInfo);
const helper = new SnapshotHelper(
testInfo, 'toHaveScreenshot', locator, snapshotPathResolver, 'png',
{
_comparator: config?._comparator,
maxDiffPixels: config?.maxDiffPixels,
maxDiffPixelRatio: config?.maxDiffPixelRatio,
threshold: config?.threshold,
},
nameOrOptions, optOptions);
configOptions, nameOrOptions, optOptions);
if (!helper.snapshotPath.toLowerCase().endsWith('.png'))
throw new Error(`Screenshot name "${path.basename(helper.snapshotPath)}" must have '.png' extension`);
expectTypes(pageOrLocator, ['Page', 'Locator'], 'toHaveScreenshot');
return await zones.preserve(async () => {
// Loading from filesystem resets zones.
const style = await loadScreenshotStyles(helper.allOptions.stylePath || config?.stylePath);
return toHaveScreenshotContinuation.call(this, helper, page, locator, config, style);
const style = await loadScreenshotStyles(helper.options.stylePath);
return toHaveScreenshotContinuation.call(this, helper, page, locator, style);
});
}
async function toHaveScreenshotContinuation(
this: ExpectMatcherContext,
helper: SnapshotHelper<HaveScreenshotOptions>,
helper: SnapshotHelper,
page: PageEx,
locator: LocatorEx | undefined,
config?: HaveScreenshotOptions,
locator: Locator | undefined,
style?: string) {
const screenshotOptions: any = {
animations: config?.animations ?? 'disabled',
scale: config?.scale ?? 'css',
caret: config?.caret ?? 'hide',
const expectScreenshotOptions: ExpectScreenshotOptions = {
locator,
animations: helper.options.animations ?? 'disabled',
caret: helper.options.caret ?? 'hide',
clip: helper.options.clip,
fullPage: helper.options.fullPage,
mask: helper.options.mask,
maskColor: helper.options.maskColor,
omitBackground: helper.options.omitBackground,
scale: helper.options.scale ?? 'css',
style,
...helper.allOptions,
mask: (helper.allOptions.mask || []) as LocatorEx[],
maskColor: helper.allOptions.maskColor,
name: undefined,
threshold: undefined,
maxDiffPixels: undefined,
maxDiffPixelRatio: undefined,
isNot: !!this.isNot,
timeout: currentExpectTimeout(helper.options),
comparator: helper.options.comparator,
maxDiffPixels: helper.options.maxDiffPixels,
maxDiffPixelRatio: helper.options.maxDiffPixelRatio,
threshold: helper.options.threshold,
};
const hasSnapshot = fs.existsSync(helper.snapshotPath);
@ -385,17 +409,8 @@ async function toHaveScreenshotContinuation(
// Having `errorMessage` means we timed out while waiting
// for screenshots not to match, so screenshots
// are actually the same in the end.
const isDifferent = !(await page._expectScreenshot({
expected: await fs.promises.readFile(helper.snapshotPath),
isNot: true,
locator,
comparatorOptions: {
...helper.comparatorOptions,
comparator: helper.comparatorOptions._comparator,
},
screenshotOptions,
timeout: currentExpectTimeout(helper.allOptions),
})).errorMessage;
expectScreenshotOptions.expected = await fs.promises.readFile(helper.snapshotPath);
const isDifferent = !(await page._expectScreenshot(expectScreenshotOptions)).errorMessage;
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
}
@ -405,15 +420,7 @@ async function toHaveScreenshotContinuation(
if (!hasSnapshot) {
// Regenerate a new screenshot by waiting until two screenshots are the same.
const timeout = currentExpectTimeout(helper.allOptions);
const { actual, previous, diff, errorMessage, log } = await page._expectScreenshot({
expected: undefined,
isNot: false,
locator,
comparatorOptions: { ...helper.comparatorOptions, comparator: helper.comparatorOptions._comparator },
screenshotOptions,
timeout,
});
const { actual, previous, diff, errorMessage, log } = await page._expectScreenshot(expectScreenshotOptions);
// We tried re-generating new snapshot but failed.
// This can be due to e.g. spinning animation, so we want to show it as a diff.
if (errorMessage)
@ -427,15 +434,8 @@ async function toHaveScreenshotContinuation(
// - snapshot exists
// - regular matcher (i.e. not a `.not`)
// - perhaps an 'all' flag to update non-matching screenshots
const expected = await fs.promises.readFile(helper.snapshotPath);
const { actual, diff, errorMessage, log } = await page._expectScreenshot({
expected,
isNot: false,
locator,
comparatorOptions: { ...helper.comparatorOptions, comparator: helper.comparatorOptions._comparator },
screenshotOptions,
timeout: currentExpectTimeout(helper.allOptions),
});
expectScreenshotOptions.expected = await fs.promises.readFile(helper.snapshotPath);
const { actual, diff, errorMessage, log } = await page._expectScreenshot(expectScreenshotOptions);
if (!errorMessage)
return helper.handleMatching();
@ -448,7 +448,7 @@ async function toHaveScreenshotContinuation(
return helper.createMatcherResult(helper.snapshotPath + ' running with --update-snapshots, writing actual.', true);
}
return helper.handleDifferent(actual, expected, undefined, diff, errorMessage, log);
return helper.handleDifferent(actual, expectScreenshotOptions.expected, undefined, diff, errorMessage, log);
}
function writeFileSync(aPath: string, content: Buffer | string) {

View file

@ -1939,26 +1939,22 @@ export type PageExpectScreenshotParams = {
frame: FrameChannel,
selector: string,
},
comparatorOptions?: {
comparator?: string,
maxDiffPixels?: number,
maxDiffPixelRatio?: number,
threshold?: number,
},
screenshotOptions?: {
fullPage?: boolean,
clip?: Rect,
omitBackground?: boolean,
caret?: 'hide' | 'initial',
animations?: 'disabled' | 'allow',
scale?: 'css' | 'device',
mask?: {
frame: FrameChannel,
selector: string,
}[],
maskColor?: string,
style?: string,
},
comparator?: string,
maxDiffPixels?: number,
maxDiffPixelRatio?: number,
threshold?: number,
fullPage?: boolean,
clip?: Rect,
omitBackground?: boolean,
caret?: 'hide' | 'initial',
animations?: 'disabled' | 'allow',
scale?: 'css' | 'device',
mask?: {
frame: FrameChannel,
selector: string,
}[],
maskColor?: string,
style?: string,
};
export type PageExpectScreenshotOptions = {
expected?: Binary,
@ -1967,26 +1963,22 @@ export type PageExpectScreenshotOptions = {
frame: FrameChannel,
selector: string,
},
comparatorOptions?: {
comparator?: string,
maxDiffPixels?: number,
maxDiffPixelRatio?: number,
threshold?: number,
},
screenshotOptions?: {
fullPage?: boolean,
clip?: Rect,
omitBackground?: boolean,
caret?: 'hide' | 'initial',
animations?: 'disabled' | 'allow',
scale?: 'css' | 'device',
mask?: {
frame: FrameChannel,
selector: string,
}[],
maskColor?: string,
style?: string,
},
comparator?: string,
maxDiffPixels?: number,
maxDiffPixelRatio?: number,
threshold?: number,
fullPage?: boolean,
clip?: Rect,
omitBackground?: boolean,
caret?: 'hide' | 'initial',
animations?: 'disabled' | 'allow',
scale?: 'css' | 'device',
mask?: {
frame: FrameChannel,
selector: string,
}[],
maskColor?: string,
style?: string,
};
export type PageExpectScreenshotResult = {
diff?: Binary,

View file

@ -1367,19 +1367,13 @@ Page:
properties:
frame: Frame
selector: string
comparatorOptions:
type: object?
properties:
comparator: string?
maxDiffPixels: number?
maxDiffPixelRatio: number?
threshold: number?
screenshotOptions:
type: object?
properties:
fullPage: boolean?
clip: Rect?
$mixin: CommonScreenshotOptions
comparator: string?
maxDiffPixels: number?
maxDiffPixelRatio: number?
threshold: number?
fullPage: boolean?
clip: Rect?
$mixin: CommonScreenshotOptions
returns:
diff: binary?
errorMessage: string?

View file

@ -22,5 +22,5 @@ type ImageComparatorOptions = { threshold?: number, maxDiffPixels?: number, maxD
export function comparePNGs(actual: Buffer, expected: Buffer, options: ImageComparatorOptions = {}): ComparatorResult {
// Strict threshold by default in our tests.
return pngComparator(actual, expected, { _comparator: 'ssim-cie94', threshold: 0, ...options });
return pngComparator(actual, expected, { comparator: 'ssim-cie94', threshold: 0, ...options });
}