mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-05 19:04:43 +03:00
feat: show expectation name as part of toHaveScreenshot title (#12612)
This patch adds snapshot file name as part of `toHaveScreenshot` and `toMatchSnapshot` step title.
This commit is contained in:
parent
5f1188d195
commit
75eef09c0d
@ -43,7 +43,7 @@ import {
|
||||
toHaveURL,
|
||||
toHaveValue
|
||||
} from './matchers/matchers';
|
||||
import { toMatchSnapshot, toHaveScreenshot } from './matchers/toMatchSnapshot';
|
||||
import { toMatchSnapshot, toHaveScreenshot, getSnapshotName } from './matchers/toMatchSnapshot';
|
||||
import type { Expect, TestError } from './types';
|
||||
import matchers from 'expect/build/matchers';
|
||||
import { currentTestInfo } from './globals';
|
||||
@ -189,6 +189,12 @@ function wrap(matcherName: string, matcher: any) {
|
||||
if (!testInfo)
|
||||
return matcher.call(this, ...args);
|
||||
|
||||
let titleSuffix = '';
|
||||
if (matcherName === 'toHaveScreenshot' || matcherName === 'toMatchSnapshot') {
|
||||
const [received, nameOrOptions, optOptions] = args;
|
||||
titleSuffix = `(${getSnapshotName(testInfo, received, nameOrOptions, optOptions)})`;
|
||||
}
|
||||
|
||||
const INTERNAL_STACK_LENGTH = 4;
|
||||
// at Object.__PWTRAP__[expect.toHaveText] (...)
|
||||
// at __EXTERNAL_MATCHER_TRAP__ (...)
|
||||
@ -202,7 +208,7 @@ function wrap(matcherName: string, matcher: any) {
|
||||
const step = testInfo._addStep({
|
||||
location: frame && frame.file ? { file: path.resolve(process.cwd(), frame.file), line: frame.line || 0, column: frame.column || 0 } : undefined,
|
||||
category: 'expect',
|
||||
title: customMessage || `expect${isSoft ? '.soft' : ''}${this.isNot ? '.not' : ''}.${matcherName}`,
|
||||
title: customMessage || `expect${isSoft ? '.soft' : ''}${this.isNot ? '.not' : ''}.${matcherName}${titleSuffix}`,
|
||||
canHaveChildren: true,
|
||||
forceNoParent: false
|
||||
});
|
||||
|
@ -38,6 +38,19 @@ type SyncExpectationResult = {
|
||||
type NameOrSegments = string | string[];
|
||||
const SNAPSHOT_COUNTER = Symbol('noname-snapshot-counter');
|
||||
|
||||
export function getSnapshotName(
|
||||
testInfo: TestInfoImpl,
|
||||
received: any,
|
||||
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & MatchSnapshotOptions = {},
|
||||
optOptions: MatchSnapshotOptions = {}
|
||||
) {
|
||||
const anonymousSnapshotExtension = typeof received === 'string' || Buffer.isBuffer(received) ? determineFileExtension(received) : 'png';
|
||||
const helper = new SnapshotHelper(
|
||||
testInfo, anonymousSnapshotExtension, {},
|
||||
nameOrOptions, optOptions, true /* dryRun */);
|
||||
return path.basename(helper.snapshotPath);
|
||||
}
|
||||
|
||||
class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||
readonly testInfo: TestInfoImpl;
|
||||
readonly expectedPath: string;
|
||||
@ -56,6 +69,7 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||
configOptions: ImageComparatorOptions,
|
||||
nameOrOptions: NameOrSegments | { name?: NameOrSegments } & T,
|
||||
optOptions: T,
|
||||
dryRun: boolean = false,
|
||||
) {
|
||||
let options: T;
|
||||
let name: NameOrSegments | undefined;
|
||||
@ -68,11 +82,13 @@ class SnapshotHelper<T extends ImageComparatorOptions> {
|
||||
delete (options as any).name;
|
||||
}
|
||||
if (!name) {
|
||||
(testInfo as any)[SNAPSHOT_COUNTER] = ((testInfo as any)[SNAPSHOT_COUNTER] || 0) + 1;
|
||||
(testInfo as any)[SNAPSHOT_COUNTER] = ((testInfo as any)[SNAPSHOT_COUNTER] || 0);
|
||||
const fullTitleWithoutSpec = [
|
||||
...testInfo.titlePath.slice(1),
|
||||
(testInfo as any)[SNAPSHOT_COUNTER],
|
||||
(testInfo as any)[SNAPSHOT_COUNTER] + 1,
|
||||
].join(' ');
|
||||
if (!dryRun)
|
||||
++(testInfo as any)[SNAPSHOT_COUNTER];
|
||||
name = sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)) + '.' + anonymousSnapshotExtension;
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,44 @@ test('should fail to screenshot a page with infinite animation', async ({ runInl
|
||||
expect(fs.existsSync(testInfo.outputPath('a.spec.js-snapshots', 'is-a-test-1.png'))).toBe(false);
|
||||
});
|
||||
|
||||
test('should report toHaveScreenshot step with expectation name in title', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'reporter.ts': `
|
||||
class Reporter {
|
||||
onStepBegin(test, result, step) {
|
||||
console.log('%% begin ' + step.title);
|
||||
}
|
||||
}
|
||||
module.exports = Reporter;
|
||||
`,
|
||||
'playwright.config.ts': `
|
||||
module.exports = {
|
||||
reporter: './reporter',
|
||||
};
|
||||
`,
|
||||
...files,
|
||||
'a.spec.js': `
|
||||
const { test } = require('./helper');
|
||||
test('is a test', async ({ page }) => {
|
||||
// Named expectation.
|
||||
await expect(page).toHaveScreenshot('foo.png', { timeout: 2000 });
|
||||
// Anonymous expectation.
|
||||
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
||||
});
|
||||
`
|
||||
}, { 'reporter': '', 'workers': 1, 'update-snapshots': true });
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.output.split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
||||
`%% begin Before Hooks`,
|
||||
`%% begin browserContext.newPage`,
|
||||
`%% begin expect.toHaveScreenshot(foo.png)`,
|
||||
`%% begin expect.toHaveScreenshot(is-a-test-1.png)`,
|
||||
`%% begin After Hooks`,
|
||||
`%% begin browserContext.close`,
|
||||
]);
|
||||
});
|
||||
|
||||
test('should not fail when racing with navigation', async ({ runInlineTest }, testInfo) => {
|
||||
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
||||
const result = await runInlineTest({
|
||||
|
Loading…
Reference in New Issue
Block a user