feat(docker): use the __screenshots__ dir for snapshots by default (#17311)
This patch opts into the `__screnshots__` folder snapshot management
for docker.
With this patch, docker-originating snapshots will be stored in the
following folder:
```
{testDir}/__screenshots__/{projectName}/{testFilePath}/{snapshotName}
```
Where `{testFilePath}` is a test file path relative to `testDir`
Drive-by: introduce and document the `PLAYWRIGHT_DOCKER` environment
variable that enables docker integration.
This commit is contained in:
parent
68072a5d5c
commit
4f11a4d5e7
|
|
@ -193,3 +193,18 @@ Docker integration usage:
|
||||||
```bash js
|
```bash js
|
||||||
npx playwright docker stop
|
npx playwright docker stop
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Playwright Test sets `PLAYWRIGHT_DOCKER` environment variable when it uses Docker integration.
|
||||||
|
You can use this variable to customize config or tests behavior, for example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// playwright.config.ts
|
||||||
|
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
// Ignore all snapshot expectations when running outside
|
||||||
|
// of docker integration.
|
||||||
|
ignoreSnapshots: !process.env.PLAYWRIGHT_DOCKER,
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ function addTestCommand(program: Command, isDocker: boolean) {
|
||||||
command.option('-x', `Stop after the first failure`);
|
command.option('-x', `Stop after the first failure`);
|
||||||
command.action(async (args, opts) => {
|
command.action(async (args, opts) => {
|
||||||
try {
|
try {
|
||||||
|
isDocker = isDocker || !!process.env.PLAYWRIGHT_DOCKER;
|
||||||
if (isDocker && !process.env.PW_TS_ESM_ON) {
|
if (isDocker && !process.env.PW_TS_ESM_ON) {
|
||||||
console.log(colors.dim('Using docker container to run browsers.'));
|
console.log(colors.dim('Using docker container to run browsers.'));
|
||||||
await docker.ensureDockerEngineIsRunningOrDie();
|
await docker.ensureDockerEngineIsRunningOrDie();
|
||||||
|
|
@ -139,7 +140,7 @@ function addTestCommand(program: Command, isDocker: boolean) {
|
||||||
process.env.PW_TEST_CONNECT_HEADERS = JSON.stringify({
|
process.env.PW_TEST_CONNECT_HEADERS = JSON.stringify({
|
||||||
'x-playwright-proxy': '*',
|
'x-playwright-proxy': '*',
|
||||||
});
|
});
|
||||||
process.env.PW_TEST_SNAPSHOT_SUFFIX = 'docker';
|
process.env.PLAYWRIGHT_DOCKER = '1';
|
||||||
}
|
}
|
||||||
await runTests(args, opts);
|
await runTests(args, opts);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ export const test = _baseTest.extend<TestFixtures, WorkerFixtures>({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_snapshotSuffix: [process.env.PW_TEST_SNAPSHOT_SUFFIX ?? process.platform, { scope: 'worker' }],
|
_snapshotSuffix: [process.platform, { scope: 'worker' }],
|
||||||
|
|
||||||
_setupContextOptionsAndArtifacts: [async ({ playwright, _snapshotSuffix, _combinedContextOptions, _browserOptions, _artifactsDir, trace, screenshot, actionTimeout, navigationTimeout }, use, testInfo) => {
|
_setupContextOptionsAndArtifacts: [async ({ playwright, _snapshotSuffix, _combinedContextOptions, _browserOptions, _artifactsDir, trace, screenshot, actionTimeout, navigationTimeout }, use, testInfo) => {
|
||||||
testInfo.snapshotSuffix = _snapshotSuffix;
|
testInfo.snapshotSuffix = _snapshotSuffix;
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,12 @@ export class Loader {
|
||||||
const outputDir = takeFirst(projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
|
const outputDir = takeFirst(projectConfig.outputDir, config.outputDir, path.join(throwawayArtifactsPath, 'test-results'));
|
||||||
const snapshotDir = takeFirst(projectConfig.snapshotDir, config.snapshotDir, testDir);
|
const snapshotDir = takeFirst(projectConfig.snapshotDir, config.snapshotDir, testDir);
|
||||||
const name = takeFirst(projectConfig.name, config.name, '');
|
const name = takeFirst(projectConfig.name, config.name, '');
|
||||||
const screenshotsDir = takeFirst((projectConfig as any).screenshotsDir, (config as any).screenshotsDir, path.join(testDir, '__screenshots__', process.platform, name));
|
|
||||||
|
let screenshotsDir = takeFirst((projectConfig as any).screenshotsDir, (config as any).screenshotsDir, path.join(testDir, '__screenshots__', process.platform, name));
|
||||||
|
if (process.env.PLAYWRIGHT_DOCKER) {
|
||||||
|
screenshotsDir = path.join(testDir, '__screenshots__', name);
|
||||||
|
process.env.PWTEST_USE_SCREENSHOTS_DIR = '1';
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
_id: '',
|
_id: '',
|
||||||
_fullConfig: fullConfig,
|
_fullConfig: fullConfig,
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ export async function toHaveScreenshot(
|
||||||
return { pass: !this.isNot, message: () => '' };
|
return { pass: !this.isNot, message: () => '' };
|
||||||
|
|
||||||
const config = (testInfo.project._expect as any)?.toHaveScreenshot;
|
const config = (testInfo.project._expect as any)?.toHaveScreenshot;
|
||||||
const snapshotPathResolver = process.env.PWTEST_USE_SCREENSHOTS_DIR_FOR_TEST
|
const snapshotPathResolver = process.env.PWTEST_USE_SCREENSHOTS_DIR
|
||||||
? testInfo._screenshotPath.bind(testInfo)
|
? testInfo._screenshotPath.bind(testInfo)
|
||||||
: testInfo.snapshotPath.bind(testInfo);
|
: testInfo.snapshotPath.bind(testInfo);
|
||||||
const helper = new SnapshotHelper(
|
const helper = new SnapshotHelper(
|
||||||
|
|
@ -315,6 +315,7 @@ export async function toHaveScreenshot(
|
||||||
if (!helper.snapshotPath.toLowerCase().endsWith('.png'))
|
if (!helper.snapshotPath.toLowerCase().endsWith('.png'))
|
||||||
throw new Error(`Screenshot name "${path.basename(helper.snapshotPath)}" must have '.png' extension`);
|
throw new Error(`Screenshot name "${path.basename(helper.snapshotPath)}" must have '.png' extension`);
|
||||||
expectTypes(pageOrLocator, ['Page', 'Locator'], 'toHaveScreenshot');
|
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 [page, locator] = pageOrLocator.constructor.name === 'Page' ? [(pageOrLocator as PageEx), undefined] : [(pageOrLocator as Locator).page() as PageEx, pageOrLocator as LocatorEx];
|
||||||
const screenshotOptions = {
|
const screenshotOptions = {
|
||||||
animations: config?.animations ?? 'disabled',
|
animations: config?.animations ?? 'disabled',
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
import { test, expect } from './npmTest';
|
import { test, expect } from './npmTest';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
|
||||||
import { TestServer } from '../../utils/testserver';
|
import { TestServer } from '../../utils/testserver';
|
||||||
|
|
||||||
// Skipping docker tests on CI on non-linux since GHA does not have
|
// Skipping docker tests on CI on non-linux since GHA does not have
|
||||||
|
|
@ -78,6 +77,18 @@ test.describe('installed image', () => {
|
||||||
expect(result).toContain('@firefox Linux');
|
expect(result).toContain('@firefox Linux');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('supports PLAYWRIGHT_DOCKER env variable', async ({ exec }) => {
|
||||||
|
await exec('npm i --foreground-scripts @playwright/test');
|
||||||
|
const result = await exec('npx playwright test docker.spec.js --grep platform --browser all', {
|
||||||
|
env: {
|
||||||
|
PLAYWRIGHT_DOCKER: '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(result).toContain('@chromium Linux');
|
||||||
|
expect(result).toContain('@webkit Linux');
|
||||||
|
expect(result).toContain('@firefox Linux');
|
||||||
|
});
|
||||||
|
|
||||||
test('all browsers work headed', async ({ exec }) => {
|
test('all browsers work headed', async ({ exec }) => {
|
||||||
await exec('npm i --foreground-scripts @playwright/test');
|
await exec('npm i --foreground-scripts @playwright/test');
|
||||||
{
|
{
|
||||||
|
|
@ -98,15 +109,14 @@ test.describe('installed image', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('screenshots have docker suffix', async ({ exec, tmpWorkspace }) => {
|
test('screenshots should use __screenshots__ folder', async ({ exec, tmpWorkspace }) => {
|
||||||
await exec('npm i --foreground-scripts @playwright/test');
|
await exec('npm i --foreground-scripts @playwright/test');
|
||||||
await exec('npx playwright docker test docker.spec.js --grep screenshot --browser all', {
|
await exec('npx playwright docker test docker.spec.js --grep screenshot --browser all', {
|
||||||
expectToExitWithError: true,
|
expectToExitWithError: true,
|
||||||
});
|
});
|
||||||
const files = await fs.promises.readdir(path.join(tmpWorkspace, 'docker.spec.js-snapshots'));
|
await expect(path.join(tmpWorkspace, '__screenshots__', 'firefox', 'docker.spec.js', 'img.png')).toExistOnFS();
|
||||||
expect(files).toContain('img-chromium-docker.png');
|
await expect(path.join(tmpWorkspace, '__screenshots__', 'chromium', 'docker.spec.js', 'img.png')).toExistOnFS();
|
||||||
expect(files).toContain('img-firefox-docker.png');
|
await expect(path.join(tmpWorkspace, '__screenshots__', 'webkit', 'docker.spec.js', 'img.png')).toExistOnFS();
|
||||||
expect(files).toContain('img-webkit-docker.png');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('port forwarding works', async ({ exec, tmpWorkspace }) => {
|
test('port forwarding works', async ({ exec, tmpWorkspace }) => {
|
||||||
|
|
|
||||||
1
tests/installation/expect.d.ts
vendored
1
tests/installation/expect.d.ts
vendored
|
|
@ -20,6 +20,7 @@ declare global {
|
||||||
namespace PlaywrightTest {
|
namespace PlaywrightTest {
|
||||||
interface Matchers<R, T> {
|
interface Matchers<R, T> {
|
||||||
toHaveLoggedSoftwareDownload(browsers: ("chromium" | "firefox" | "webkit" | "ffmpeg")[]): R;
|
toHaveLoggedSoftwareDownload(browsers: ("chromium" | "firefox" | "webkit" | "ffmpeg")[]): R;
|
||||||
|
toExistOnFS(): R;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,17 @@ const debug = debugLogger('itest');
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_expect.extend({
|
_expect.extend({
|
||||||
|
async toExistOnFS(received: any) {
|
||||||
|
if (typeof received !== 'string')
|
||||||
|
throw new Error(`Expected argument to be a string.`);
|
||||||
|
try {
|
||||||
|
await fs.promises.access(received);
|
||||||
|
return { pass: true };
|
||||||
|
} catch (e) {
|
||||||
|
return { pass: false, message: () => 'file does not exist' };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
toHaveLoggedSoftwareDownload(received: any, browsers: ('chromium' | 'firefox' | 'webkit' | 'ffmpeg')[]) {
|
toHaveLoggedSoftwareDownload(received: any, browsers: ('chromium' | 'firefox' | 'webkit' | 'ffmpeg')[]) {
|
||||||
if (typeof received !== 'string')
|
if (typeof received !== 'string')
|
||||||
throw new Error(`Expected argument to be a string.`);
|
throw new Error(`Expected argument to be a string.`);
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,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': `
|
||||||
process.env.PWTEST_USE_SCREENSHOTS_DIR_FOR_TEST = '1';
|
process.env.PWTEST_USE_SCREENSHOTS_DIR = '1';
|
||||||
module.exports = {
|
module.exports = {
|
||||||
screenshotsDir: '__screenshots__',
|
screenshotsDir: '__screenshots__',
|
||||||
use: { viewport: { width: ${IMG_WIDTH}, height: ${IMG_HEIGHT} }}
|
use: { viewport: { width: ${IMG_WIDTH}, height: ${IMG_HEIGHT} }}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ test('should fail with proper error when unsupported argument is given', async (
|
||||||
|
|
||||||
test('should use match snapshot paths by default', async ({ runInlineTest }, testInfo) => {
|
test('should use match snapshot paths by default', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
// The helper function `playwrightConfig` set PWTEST_USE_SCREENSHOTS_DIR_FOR_TEST env variable.
|
// The helper function `playwrightConfig` set PWTEST_USE_SCREENSHOTS env variable.
|
||||||
// Provide default config manually instead.
|
// Provide default config manually instead.
|
||||||
'playwright.config.js': `
|
'playwright.config.js': `
|
||||||
module.exports = {};
|
module.exports = {};
|
||||||
|
|
@ -1017,7 +1017,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.PWTEST_USE_SCREENSHOTS_DIR_FOR_TEST = '1';
|
process.env.PWTEST_USE_SCREENSHOTS_DIR = '1';
|
||||||
module.exports = ${JSON.stringify(obj, null, 2)}
|
module.exports = ${JSON.stringify(obj, null, 2)}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue