function options
This commit is contained in:
parent
d7020cba63
commit
4d0db5018c
|
|
@ -1751,7 +1751,7 @@ await Expect(Page.GetByTitle("Issues count")).toHaveText("25 issues");
|
|||
```
|
||||
|
||||
## test-config-snapshot-path-template
|
||||
- `type` ?<[string]>
|
||||
- `type` ?<[string]|[SnapshotPathResolver]>
|
||||
* langs: js
|
||||
|
||||
This option configures a template controlling location of snapshots generated by [`method: PageAssertions.toHaveScreenshot#1`] and [`method: SnapshotAssertions.toMatchSnapshot#1`].
|
||||
|
|
@ -1764,6 +1764,12 @@ import { defineConfig } from '@playwright/test';
|
|||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
|
||||
projects: [
|
||||
{
|
||||
// Using a function for runtime control
|
||||
snapshotPathTemplate: ({ testDir, testFilePath, arg, ext }) => `${testDir}/__screenshots__/${testFilePath}/${arg}${ext}`
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import { getPackageJsonPath, mergeObjects } from '../util';
|
|||
import type { Matcher } from '../util';
|
||||
import type { ConfigCLIOverrides } from './ipc';
|
||||
import type { FullConfig, FullProject } from '../../types/testReporter';
|
||||
import type { SnapshotPathResolver } from '../worker/testInfo';
|
||||
|
||||
export type ConfigLocation = {
|
||||
resolvedConfigFile?: string;
|
||||
|
|
@ -154,7 +155,7 @@ export class FullProjectInternal {
|
|||
readonly fullyParallel: boolean;
|
||||
readonly expect: Project['expect'];
|
||||
readonly respectGitIgnore: boolean;
|
||||
readonly snapshotPathTemplate: string;
|
||||
readonly snapshotPathTemplate: string | SnapshotPathResolver;
|
||||
readonly ignoreSnapshots: boolean;
|
||||
id = '';
|
||||
deps: FullProjectInternal[] = [];
|
||||
|
|
@ -289,4 +290,4 @@ const configInternalSymbol = Symbol('configInternalSymbol');
|
|||
|
||||
export function getProjectId(project: FullProject): string {
|
||||
return (project as any).__projectId!;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,22 @@ export type TestStage = {
|
|||
step?: TestStepInternal;
|
||||
};
|
||||
|
||||
export type SnapshotPathArgs = {
|
||||
arg: string;
|
||||
ext: string;
|
||||
platform: NodeJS.Platform;
|
||||
projectName?: string;
|
||||
snapshotDir: string;
|
||||
snapshotSuffix?: string;
|
||||
testDir: string;
|
||||
testFileDir: string;
|
||||
testFileName: string;
|
||||
testFilePath: string;
|
||||
testName: string;
|
||||
};
|
||||
|
||||
export type SnapshotPathResolver = (snapshotPathArgs: SnapshotPathArgs, testInfo: TestInfo) => string;
|
||||
|
||||
export class TestInfoImpl implements TestInfo {
|
||||
private _onStepBegin: (payload: StepBeginPayload) => void;
|
||||
private _onStepEnd: (payload: StepEndPayload) => void;
|
||||
|
|
@ -441,20 +457,35 @@ export class TestInfoImpl implements TestInfo {
|
|||
const parsedSubPath = path.parse(subPath);
|
||||
const relativeTestFilePath = path.relative(this.project.testDir, this._requireFile);
|
||||
const parsedRelativeTestFilePath = path.parse(relativeTestFilePath);
|
||||
const projectNamePathSegment = sanitizeForFilePath(this.project.name);
|
||||
const options: SnapshotPathArgs = {
|
||||
arg: path.join(parsedSubPath.dir, parsedSubPath.name),
|
||||
ext: parsedSubPath.ext,
|
||||
platform: process.platform,
|
||||
projectName: sanitizeForFilePath(this.project.name),
|
||||
snapshotDir: this.project.snapshotDir,
|
||||
snapshotSuffix: this.snapshotSuffix,
|
||||
testDir: this.project.testDir,
|
||||
testFileDir: parsedRelativeTestFilePath.dir,
|
||||
testFileName: parsedRelativeTestFilePath.base,
|
||||
testFilePath: relativeTestFilePath,
|
||||
testName: this._fsSanitizedTestName(),
|
||||
};
|
||||
|
||||
const snapshotPath = (this._projectInternal.snapshotPathTemplate || '')
|
||||
.replace(/\{(.)?testDir\}/g, '$1' + this.project.testDir)
|
||||
.replace(/\{(.)?snapshotDir\}/g, '$1' + this.project.snapshotDir)
|
||||
.replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? '$1' + this.snapshotSuffix : '')
|
||||
.replace(/\{(.)?testFileDir\}/g, '$1' + parsedRelativeTestFilePath.dir)
|
||||
.replace(/\{(.)?platform\}/g, '$1' + process.platform)
|
||||
.replace(/\{(.)?projectName\}/g, projectNamePathSegment ? '$1' + projectNamePathSegment : '')
|
||||
.replace(/\{(.)?testName\}/g, '$1' + this._fsSanitizedTestName())
|
||||
.replace(/\{(.)?testFileName\}/g, '$1' + parsedRelativeTestFilePath.base)
|
||||
.replace(/\{(.)?testFilePath\}/g, '$1' + relativeTestFilePath)
|
||||
.replace(/\{(.)?arg\}/g, '$1' + path.join(parsedSubPath.dir, parsedSubPath.name))
|
||||
.replace(/\{(.)?ext\}/g, parsedSubPath.ext ? '$1' + parsedSubPath.ext : '');
|
||||
const snapshotPath: string =
|
||||
typeof this._projectInternal.snapshotPathTemplate === 'function' ?
|
||||
this._projectInternal.snapshotPathTemplate(options, this) :
|
||||
(this._projectInternal.snapshotPathTemplate || '')
|
||||
.replace(/\{(.)?testDir\}/g, '$1' + options.testDir)
|
||||
.replace(/\{(.)?snapshotDir\}/g, '$1' + options.snapshotDir)
|
||||
.replace(/\{(.)?snapshotSuffix\}/g, options.snapshotSuffix ? '$1' + options.snapshotSuffix : '')
|
||||
.replace(/\{(.)?testFileDir\}/g, '$1' + options.testFileDir)
|
||||
.replace(/\{(.)?platform\}/g, '$1' + options.platform)
|
||||
.replace(/\{(.)?projectName\}/g, options.projectName ? '$1' + options.projectName : '')
|
||||
.replace(/\{(.)?testName\}/g, '$1' + options.testName)
|
||||
.replace(/\{(.)?testFileName\}/g, '$1' + options.testFileName)
|
||||
.replace(/\{(.)?testFilePath\}/g, '$1' + options.testFilePath)
|
||||
.replace(/\{(.)?arg\}/g, '$1' + options.arg)
|
||||
.replace(/\{(.)?ext\}/g, options.ext ? '$1' + options.ext : '');
|
||||
|
||||
return path.normalize(path.resolve(this._configInternal.configDir, snapshotPath));
|
||||
}
|
||||
|
|
|
|||
16
packages/playwright/types/test.d.ts
vendored
16
packages/playwright/types/test.d.ts
vendored
|
|
@ -417,6 +417,12 @@ interface TestProject<TestArgs = {}, WorkerArgs = {}> {
|
|||
* export default defineConfig({
|
||||
* testDir: './tests',
|
||||
* snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
|
||||
* projects: [
|
||||
* {
|
||||
* // Using a function for runtime control
|
||||
* snapshotPathTemplate: ({ testDir, testFilePath, arg, ext }) => `${testDir}/__screenshots__/${testFilePath}/${arg}${ext}`
|
||||
* },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
|
|
@ -498,7 +504,7 @@ interface TestProject<TestArgs = {}, WorkerArgs = {}> {
|
|||
* 1. Since `snapshotPathTemplate` resolves to relative path, it will be resolved relative to `configDir`.
|
||||
* 1. Forward slashes `"/"` can be used as path separators on any platform.
|
||||
*/
|
||||
snapshotPathTemplate?: string;
|
||||
snapshotPathTemplate?: string|SnapshotPathResolver;
|
||||
|
||||
/**
|
||||
* Name of a project that needs to run after this and all dependent projects have finished. Teardown is useful to
|
||||
|
|
@ -1479,6 +1485,12 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
|
|||
* export default defineConfig({
|
||||
* testDir: './tests',
|
||||
* snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
|
||||
* projects: [
|
||||
* {
|
||||
* // Using a function for runtime control
|
||||
* snapshotPathTemplate: ({ testDir, testFilePath, arg, ext }) => `${testDir}/__screenshots__/${testFilePath}/${arg}${ext}`
|
||||
* },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
|
|
@ -1560,7 +1572,7 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
|
|||
* 1. Since `snapshotPathTemplate` resolves to relative path, it will be resolved relative to `configDir`.
|
||||
* 1. Forward slashes `"/"` can be used as path separators on any platform.
|
||||
*/
|
||||
snapshotPathTemplate?: string;
|
||||
snapshotPathTemplate?: string|SnapshotPathResolver;
|
||||
|
||||
/**
|
||||
* Directory that will be recursively scanned for test files. Defaults to the directory of the configuration file.
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import path from 'path';
|
|||
import fs from 'fs';
|
||||
import { test, expect } from './playwright-test-fixtures';
|
||||
|
||||
const SEPARATOR = '==== 8< ---- ';
|
||||
async function getSnapshotPaths(runInlineTest, testInfo, playwrightConfig, pathArgs) {
|
||||
const SEPARATOR = '==== 8< ---- ';
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `
|
||||
module.exports = ${JSON.stringify(playwrightConfig, null, 2)}
|
||||
|
|
@ -106,6 +106,53 @@ test('tokens should expand property', async ({ runInlineTest }, testInfo) => {
|
|||
expect.soft(snapshotPath['testName']).toBe('suite-test-should-work');
|
||||
});
|
||||
|
||||
test('supports function arg', async ({ runInlineTest }, testInfo) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `
|
||||
module.exports = {
|
||||
projects: [
|
||||
{
|
||||
name: 'proj',
|
||||
snapshotPathTemplate: (args) => {
|
||||
console.log(JSON.stringify(args));
|
||||
return 'path/to/snapshot';
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
'a.spec.ts': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('is a test', async ({ }, testInfo) => {
|
||||
console.log(${JSON.stringify(SEPARATOR)})
|
||||
const snapshotPath = testInfo.snapshotPath('foo', 'bar.png');
|
||||
console.log(${JSON.stringify(SEPARATOR)});
|
||||
console.log(JSON.stringify({ snapshotPath }));
|
||||
console.log(${JSON.stringify(SEPARATOR)});
|
||||
});
|
||||
`
|
||||
});
|
||||
const output = result.output.split(SEPARATOR).slice(1, -1).map(json => JSON.parse(json));
|
||||
expect.soft(output).toEqual([
|
||||
{
|
||||
arg: 'foo/bar',
|
||||
ext: '.png',
|
||||
platform: process.platform,
|
||||
projectName: 'proj',
|
||||
snapshotDir: testInfo.outputPath(test.name),
|
||||
snapshotSuffix: process.platform,
|
||||
testDir: testInfo.outputDir,
|
||||
testFileDir: '',
|
||||
testFileName: 'a.spec.ts',
|
||||
testFilePath: 'a.spec.ts',
|
||||
testName: 'is-a-test',
|
||||
},
|
||||
{
|
||||
snapshotPath: testInfo.outputPath('path/to/snapshot')
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test('args array should work', async ({ runInlineTest }, testInfo) => {
|
||||
const snapshotPath = await getSnapshotPaths(runInlineTest, testInfo, {
|
||||
projects: [{
|
||||
|
|
|
|||
Loading…
Reference in a new issue