2022-02-28 23:25:59 +03:00
|
|
|
/**
|
|
|
|
* Copyright Microsoft Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import * as fs from 'fs';
|
2022-04-19 06:20:49 +03:00
|
|
|
import { PNG } from 'playwright-core/lib/utilsBundle';
|
2022-02-28 23:25:59 +03:00
|
|
|
import * as path from 'path';
|
|
|
|
import { pathToFileURL } from 'url';
|
|
|
|
import { test, expect, stripAnsi, createImage, paintBlackPixels } from './playwright-test-fixtures';
|
2022-11-08 00:32:46 +03:00
|
|
|
import { comparePNGs } from '../config/comparator';
|
2022-02-28 23:25:59 +03:00
|
|
|
|
|
|
|
test.describe.configure({ mode: 'parallel' });
|
|
|
|
|
|
|
|
const IMG_WIDTH = 1280;
|
|
|
|
const IMG_HEIGHT = 720;
|
|
|
|
const whiteImage = createImage(IMG_WIDTH, IMG_HEIGHT, 255, 255, 255);
|
|
|
|
const redImage = createImage(IMG_WIDTH, IMG_HEIGHT, 255, 0, 0);
|
|
|
|
const greenImage = createImage(IMG_WIDTH, IMG_HEIGHT, 0, 255, 0);
|
|
|
|
const blueImage = createImage(IMG_WIDTH, IMG_HEIGHT, 0, 0, 255);
|
|
|
|
|
|
|
|
test('should fail to screenshot a page with infinite animation', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
|
|
|
const result = await runInlineTest({
|
2022-03-11 19:45:36 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
expect: {
|
2022-04-14 23:22:42 +03:00
|
|
|
toHaveScreenshot: {
|
2022-03-11 19:45:36 +03:00
|
|
|
animations: 'allow',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await page.goto('${infiniteAnimationURL}');
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
2022-04-19 17:43:18 +03:00
|
|
|
expect(stripAnsi(result.output)).toContain(`Timeout 2000ms exceeded`);
|
2022-03-12 09:40:28 +03:00
|
|
|
expect(stripAnsi(result.output)).toContain(`expect.toHaveScreenshot with timeout 2000ms`);
|
2022-03-22 01:10:33 +03:00
|
|
|
expect(stripAnsi(result.output)).toContain(`generating new stable screenshot expectation`);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-actual.png'))).toBe(true);
|
2022-03-11 19:46:13 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-expected.png'))).toBe(false);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-previous.png'))).toBe(true);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-diff.png'))).toBe(true);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('a.spec.js-snapshots', 'is-a-test-1.png'))).toBe(false);
|
|
|
|
});
|
|
|
|
|
2022-03-11 19:45:36 +03:00
|
|
|
test('should disable animations by default', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const cssTransitionURL = pathToFileURL(path.join(__dirname, '../assets/css-transition.html'));
|
|
|
|
const result = await runInlineTest({
|
2022-04-14 02:13:30 +03:00
|
|
|
...playwrightConfig({}),
|
2022-03-11 19:45:36 +03:00
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
|
|
|
await page.goto('${cssTransitionURL}');
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
2022-03-11 19:45:36 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
2022-05-24 21:34:29 +03:00
|
|
|
test.describe('expect config animations option', () => {
|
|
|
|
test('disabled', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const cssTransitionURL = pathToFileURL(path.join(__dirname, '../assets/css-transition.html'));
|
|
|
|
const result = await runInlineTest({
|
|
|
|
...playwrightConfig({
|
|
|
|
expect: { toHaveScreenshot: { animations: 'disabled' } },
|
|
|
|
}),
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
|
|
|
await page.goto('${cssTransitionURL}');
|
|
|
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('allow', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const cssTransitionURL = pathToFileURL(path.join(__dirname, '../assets/css-transition.html'));
|
|
|
|
const result = await runInlineTest({
|
|
|
|
...playwrightConfig({
|
|
|
|
expect: { toHaveScreenshot: { animations: 'allow' } },
|
|
|
|
}),
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
|
|
|
await page.goto('${cssTransitionURL}');
|
|
|
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.output).toContain('is-a-test-1-diff.png');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2022-04-19 17:43:18 +03:00
|
|
|
test('should fail with proper error when unsupported argument is given', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const cssTransitionURL = pathToFileURL(path.join(__dirname, '../assets/css-transition.html'));
|
|
|
|
const result = await runInlineTest({
|
|
|
|
...playwrightConfig({}),
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
|
|
|
await page.goto('${cssTransitionURL}');
|
|
|
|
await expect(page).toHaveScreenshot({
|
|
|
|
clip: {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: 0,
|
|
|
|
height: 0,
|
|
|
|
},
|
|
|
|
timeout: 2000,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(stripAnsi(result.output)).toContain(`Expected options.clip.width not to be 0`);
|
|
|
|
});
|
|
|
|
|
2022-04-01 22:28:40 +03:00
|
|
|
test('should have scale:css by default', async ({ runInlineTest }, testInfo) => {
|
2022-03-11 19:45:36 +03:00
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 19:45:36 +03:00
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ browser }) => {
|
|
|
|
const context = await browser.newContext({
|
|
|
|
viewport: { width: ${IMG_WIDTH}, height: ${IMG_HEIGHT} },
|
|
|
|
deviceScaleFactor: 2,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-03-11 19:45:36 +03:00
|
|
|
await context.close();
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
|
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__', 'a.spec.js', 'snapshot.png');
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(fs.readFileSync(snapshotOutputPath), whiteImage)).toBe(null);
|
2022-03-11 19:45:36 +03:00
|
|
|
});
|
|
|
|
|
2022-04-14 23:22:42 +03:00
|
|
|
test('should ignore non-documented options in toHaveScreenshot config', async ({ runInlineTest }, testInfo) => {
|
2022-03-11 19:45:36 +03:00
|
|
|
const result = await runInlineTest({
|
|
|
|
...playwrightConfig({
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 19:45:36 +03:00
|
|
|
expect: {
|
2022-04-14 23:22:42 +03:00
|
|
|
toHaveScreenshot: {
|
2022-03-11 19:45:36 +03:00
|
|
|
clip: { x: 0, y: 0, width: 10, height: 10 },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-03-11 19:45:36 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
|
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__', 'a.spec.js', 'snapshot.png');
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(fs.readFileSync(snapshotOutputPath), whiteImage)).toBe(null);
|
2022-03-11 19:45:36 +03:00
|
|
|
});
|
|
|
|
|
2022-04-14 23:22:42 +03:00
|
|
|
test('should report toHaveScreenshot step with expectation name in title', async ({ runInlineTest }) => {
|
2022-03-10 07:09:45 +03:00
|
|
|
const result = await runInlineTest({
|
|
|
|
'reporter.ts': `
|
|
|
|
class Reporter {
|
2022-03-31 07:52:00 +03:00
|
|
|
onStepEnd(test, result, step) {
|
|
|
|
console.log('%% end ' + step.title);
|
2022-03-10 07:09:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = Reporter;
|
|
|
|
`,
|
2022-04-14 02:13:30 +03:00
|
|
|
...playwrightConfig({ reporter: './reporter' }),
|
2022-03-10 07:09:45 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-03-10 07:09:45 +03:00
|
|
|
// Named expectation.
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('foo.png', { timeout: 2000 });
|
2022-03-10 07:09:45 +03:00
|
|
|
// Anonymous expectation.
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({ timeout: 2000 });
|
2022-03-10 07:09:45 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'reporter': '', 'workers': 1, 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
expect(result.output.split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
2022-03-31 07:52:00 +03:00
|
|
|
`%% end browserContext.newPage`,
|
|
|
|
`%% end Before Hooks`,
|
2022-04-14 23:22:42 +03:00
|
|
|
`%% end expect.toHaveScreenshot(foo.png)`,
|
|
|
|
`%% end expect.toHaveScreenshot(is-a-test-1.png)`,
|
2022-03-31 07:52:00 +03:00
|
|
|
`%% end browserContext.close`,
|
|
|
|
`%% end After Hooks`,
|
2022-03-10 07:09:45 +03:00
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
2022-02-28 23:25:59 +03:00
|
|
|
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({
|
2022-03-11 03:50:26 +03:00
|
|
|
...playwrightConfig({
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 03:50:26 +03:00
|
|
|
}),
|
|
|
|
'__screenshots__/a.spec.js/snapshot.png': createImage(10, 10, 255, 0, 0),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await Promise.all([
|
|
|
|
page.goto('${infiniteAnimationURL}'),
|
2022-04-14 23:22:42 +03:00
|
|
|
expect(page).toHaveScreenshot({
|
2022-02-28 23:25:59 +03:00
|
|
|
name: 'snapshot.png',
|
2022-03-04 22:02:59 +03:00
|
|
|
animations: "disabled",
|
2022-02-28 23:25:59 +03:00
|
|
|
clip: { x: 0, y: 0, width: 10, height: 10 },
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
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 result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await page.goto('${infiniteAnimationURL}');
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({
|
2022-03-04 22:02:59 +03:00
|
|
|
animations: "disabled",
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(0);
|
2022-03-11 03:50:26 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('__screenshots__', 'a.spec.js', 'is-a-test-1.png'))).toBe(true);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should support clip option for page', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': createImage(50, 50, 255, 255, 255),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({
|
2022-02-28 23:25:59 +03:00
|
|
|
name: 'snapshot.png',
|
|
|
|
clip: { x: 0, y: 0, width: 50, height: 50, },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should support omitBackground option for locator', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await page.evaluate(() => {
|
|
|
|
document.body.style.setProperty('width', '100px');
|
|
|
|
document.body.style.setProperty('height', '100px');
|
|
|
|
});
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page.locator('body')).toHaveScreenshot({
|
2022-02-28 23:25:59 +03:00
|
|
|
name: 'snapshot.png',
|
|
|
|
omitBackground: true,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
expect(result.exitCode).toBe(0);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotPath = testInfo.outputPath('__screenshots__', 'a.spec.js', 'snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(snapshotPath)).toBe(true);
|
|
|
|
const png = PNG.sync.read(fs.readFileSync(snapshotPath));
|
|
|
|
expect.soft(png.width, 'image width must be 100').toBe(100);
|
|
|
|
expect.soft(png.height, 'image height must be 100').toBe(100);
|
|
|
|
expect.soft(png.data[0], 'image R must be 0').toBe(0);
|
|
|
|
expect.soft(png.data[1], 'image G must be 0').toBe(0);
|
|
|
|
expect.soft(png.data[2], 'image B must be 0').toBe(0);
|
|
|
|
expect.soft(png.data[3], 'image A must be 0').toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should fail to screenshot an element with infinite animation', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
|
|
|
const result = await runInlineTest({
|
2022-03-11 19:45:36 +03:00
|
|
|
...playwrightConfig({
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 19:45:36 +03:00
|
|
|
projects: [{
|
|
|
|
expect: {
|
2022-04-14 23:22:42 +03:00
|
|
|
toHaveScreenshot: {
|
2022-03-11 19:45:36 +03:00
|
|
|
animations: 'allow',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}],
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await page.goto('${infiniteAnimationURL}');
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page.locator('body')).toHaveScreenshot({ timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
2022-04-19 17:43:18 +03:00
|
|
|
expect(stripAnsi(result.output)).toContain(`Timeout 2000ms exceeded`);
|
2022-03-15 04:01:13 +03:00
|
|
|
expect(stripAnsi(result.output)).toContain(`expect.toHaveScreenshot with timeout 2000ms`);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-previous.png'))).toBe(true);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-actual.png'))).toBe(true);
|
2022-03-11 19:46:13 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-expected.png'))).toBe(false);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-diff.png'))).toBe(true);
|
2022-03-11 03:50:26 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('__screenshots__', 'a.spec.js', 'is-a-test-1.png'))).toBe(false);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should fail to screenshot an element that keeps moving', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const infiniteAnimationURL = pathToFileURL(path.join(__dirname, '../assets/rotate-z.html'));
|
|
|
|
const result = await runInlineTest({
|
2022-03-11 19:45:36 +03:00
|
|
|
...playwrightConfig({
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 19:45:36 +03:00
|
|
|
expect: {
|
2022-04-14 23:22:42 +03:00
|
|
|
toHaveScreenshot: {
|
2022-03-11 19:45:36 +03:00
|
|
|
animations: 'allow',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await page.goto('${infiniteAnimationURL}');
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page.locator('div')).toHaveScreenshot({ timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(stripAnsi(result.output)).toContain(`Timeout 2000ms exceeded`);
|
|
|
|
expect(stripAnsi(result.output)).toContain(`element is not stable - waiting`);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-actual.png'))).toBe(false);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-expected.png'))).toBe(false);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-diff.png'))).toBe(false);
|
2022-03-11 03:50:26 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('__screenshots__', 'a.spec.js', 'is-a-test-1.png'))).toBe(false);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should generate default name', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot();
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-actual.png'))).toBe(true);
|
2022-03-11 03:50:26 +03:00
|
|
|
expect(fs.existsSync(testInfo.outputPath('__screenshots__', 'a.spec.js', 'is-a-test-1.png'))).toBe(true);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should compile with different option combinations', async ({ runTSC }) => {
|
|
|
|
const result = await runTSC({
|
2022-04-01 22:28:40 +03:00
|
|
|
'playwright.config.ts': `
|
2022-04-14 23:22:42 +03:00
|
|
|
//@no-header
|
2022-04-01 22:28:40 +03:00
|
|
|
import type { PlaywrightTestConfig } from '@playwright/test';
|
|
|
|
const config: PlaywrightTestConfig = {
|
|
|
|
expect: {
|
|
|
|
timeout: 10000,
|
|
|
|
toHaveScreenshot: {
|
|
|
|
threshold: 0.2,
|
|
|
|
maxDiffPixels: 10,
|
|
|
|
maxDiffPixelRatio: 0.2,
|
|
|
|
animations: "allow",
|
|
|
|
caret: "hide",
|
|
|
|
scale: "css",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
export default config;
|
|
|
|
`,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.ts': `
|
|
|
|
const { test } = pwt;
|
|
|
|
test('is a test', async ({ page }) => {
|
|
|
|
await expect(page).toHaveScreenshot();
|
2022-05-16 17:53:46 +03:00
|
|
|
await expect(page).toHaveScreenshot('img.png');
|
|
|
|
await expect(page).toHaveScreenshot('img.png', { threshold: 0.2, caret: 'initial' });
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page.locator('body')).toHaveScreenshot({ threshold: 0.2 });
|
2022-03-04 10:17:31 +03:00
|
|
|
await expect(page).toHaveScreenshot({ maxDiffPixelRatio: 0.2 });
|
2022-02-28 23:25:59 +03:00
|
|
|
await expect(page).toHaveScreenshot({
|
|
|
|
threshold: 0.2,
|
2022-03-04 10:17:31 +03:00
|
|
|
maxDiffPixels: 10,
|
|
|
|
maxDiffPixelRatio: 0.2,
|
2022-03-04 22:02:59 +03:00
|
|
|
animations: "disabled",
|
2022-02-28 23:25:59 +03:00
|
|
|
omitBackground: true,
|
2022-04-01 22:28:40 +03:00
|
|
|
caret: "initial",
|
|
|
|
scale: "device",
|
2022-02-28 23:25:59 +03:00
|
|
|
timeout: 1000,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should fail when screenshot is different size', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': createImage(22, 33),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
2022-03-22 01:10:33 +03:00
|
|
|
expect(stripAnsi(result.output)).toContain(`verifying given screenshot expectation`);
|
|
|
|
expect(stripAnsi(result.output)).toContain(`captured a stable screenshot`);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(result.output).toContain('Expected an image 22px by 33px, received 1280px by 720px.');
|
|
|
|
});
|
|
|
|
|
2022-03-12 09:40:28 +03:00
|
|
|
test('should fail when given non-png snapshot name', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-12 09:40:28 +03:00
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.jpeg');
|
2022-03-12 09:40:28 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(stripAnsi(result.output)).toContain(`Screenshot name "snapshot.jpeg" must have '.png' extension`);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should fail when given buffer', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-04-14 02:13:30 +03:00
|
|
|
...playwrightConfig({}),
|
2022-03-12 09:40:28 +03:00
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(Buffer.from([1])).toHaveScreenshot();
|
2022-03-12 09:40:28 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(stripAnsi(result.output)).toContain(`toHaveScreenshot can be only used with Page or Locator objects`);
|
|
|
|
});
|
|
|
|
|
2022-02-28 23:25:59 +03:00
|
|
|
test('should fail when screenshot is different pixels', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': paintBlackPixels(whiteImage, 12345),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.output).toContain('Screenshot comparison failed');
|
2022-03-05 05:55:48 +03:00
|
|
|
expect(result.output).toContain('12345 pixels');
|
2022-03-12 09:40:28 +03:00
|
|
|
expect(result.output).toContain('Call log');
|
2022-03-05 05:55:48 +03:00
|
|
|
expect(result.output).toContain('ratio 0.02');
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(result.output).toContain('Expected:');
|
|
|
|
expect(result.output).toContain('Received:');
|
|
|
|
});
|
|
|
|
|
|
|
|
test('doesn\'t create comparison artifacts in an output folder for passed negated snapshot matcher', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': blueImage,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
const outputText = stripAnsi(result.output);
|
|
|
|
const expectedSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-expected.png');
|
|
|
|
const actualSnapshotArtifactPath = testInfo.outputPath('test-results', 'a-is-a-test', 'snapshot-actual.png');
|
|
|
|
expect(outputText).not.toContain(`Expected: ${expectedSnapshotArtifactPath}`);
|
|
|
|
expect(outputText).not.toContain(`Received: ${actualSnapshotArtifactPath}`);
|
|
|
|
expect(fs.existsSync(expectedSnapshotArtifactPath)).toBe(false);
|
|
|
|
expect(fs.existsSync(actualSnapshotArtifactPath)).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should fail on same snapshots with negate matcher', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': whiteImage,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).not.toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.output).toContain('Screenshot comparison failed:');
|
|
|
|
expect(result.output).toContain('Expected result should be different from the actual one.');
|
|
|
|
});
|
|
|
|
|
2022-09-01 15:34:36 +03:00
|
|
|
test('should not fail if --ignore-snapshots is passed', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-09-01 15:34:36 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': redImage,
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'ignore-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
2022-02-28 23:25:59 +03:00
|
|
|
test('should write missing expectations locally twice and continue', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
|
|
|
await expect(page).toHaveScreenshot('snapshot2.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
console.log('Here we are!');
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.failed).toBe(1);
|
|
|
|
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshot1OutputPath = testInfo.outputPath('__screenshots__', 'a.spec.js', 'snapshot.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`Error: A snapshot doesn't exist at ${snapshot1OutputPath}, writing actual`);
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(fs.readFileSync(snapshot1OutputPath), whiteImage)).toBe(null);
|
2022-02-28 23:25:59 +03:00
|
|
|
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshot2OutputPath = testInfo.outputPath('__screenshots__', 'a.spec.js', 'snapshot2.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`Error: A snapshot doesn't exist at ${snapshot2OutputPath}, writing actual`);
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(fs.readFileSync(snapshot2OutputPath), whiteImage)).toBe(null);
|
2022-02-28 23:25:59 +03:00
|
|
|
|
|
|
|
expect(result.output).toContain('Here we are!');
|
|
|
|
|
|
|
|
const stackLines = stripAnsi(result.output).split('\n').filter(line => line.includes(' at ')).filter(line => !line.includes(testInfo.outputPath()));
|
2022-03-11 03:50:26 +03:00
|
|
|
expect(result.output).toContain('a.spec.js:5');
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(stackLines.length).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('shouldn\'t write missing expectations locally for negated matcher', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(1);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`A snapshot doesn't exist at ${snapshotOutputPath}, matchers using ".not" won\'t write them automatically.`);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(snapshotOutputPath)).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should update snapshot with the update-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': blueImage,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(result.output).toContain(`${snapshotOutputPath} is re-generated, writing actual.`);
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(fs.readFileSync(snapshotOutputPath), whiteImage)).toBe(null);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('shouldn\'t update snapshot with the update-snapshots flag for negated matcher', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const EXPECTED_SNAPSHOT = blueImage;
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.readFileSync(snapshotOutputPath).equals(EXPECTED_SNAPSHOT)).toBe(true);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should silently write missing expectations locally with the update-snapshots flag', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`A snapshot doesn't exist at ${snapshotOutputPath}, writing actual`);
|
2022-02-28 23:25:59 +03:00
|
|
|
const data = fs.readFileSync(snapshotOutputPath);
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(data, whiteImage)).toBe(null);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should not write missing expectations locally with the update-snapshots flag for negated matcher', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).not.toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(1);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`A snapshot doesn't exist at ${snapshotOutputPath}, matchers using ".not" won\'t write them automatically.`);
|
2022-02-28 23:25:59 +03:00
|
|
|
expect(fs.existsSync(snapshotOutputPath)).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should match multiple snapshots', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/red.png': redImage,
|
|
|
|
'__screenshots__/a.spec.js/green.png': greenImage,
|
|
|
|
'__screenshots__/a.spec.js/blue.png': blueImage,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
await Promise.all([
|
|
|
|
page.evaluate(() => document.documentElement.style.setProperty('background', '#f00')),
|
2022-04-14 23:22:42 +03:00
|
|
|
expect(page).toHaveScreenshot('red.png'),
|
2022-02-28 23:25:59 +03:00
|
|
|
]);
|
|
|
|
await Promise.all([
|
|
|
|
page.evaluate(() => document.documentElement.style.setProperty('background', '#0f0')),
|
2022-04-14 23:22:42 +03:00
|
|
|
expect(page).toHaveScreenshot('green.png'),
|
2022-02-28 23:25:59 +03:00
|
|
|
]);
|
|
|
|
await Promise.all([
|
|
|
|
page.evaluate(() => document.documentElement.style.setProperty('background', '#00f')),
|
2022-04-14 23:22:42 +03:00
|
|
|
expect(page).toHaveScreenshot('blue.png'),
|
2022-02-28 23:25:59 +03:00
|
|
|
]);
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should use provided name', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/provided.png': whiteImage,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('provided.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should use provided name via options', async ({ runInlineTest }) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/provided.png': whiteImage,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({ name: 'provided.png' });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
});
|
|
|
|
|
2022-03-04 10:17:31 +03:00
|
|
|
test('should respect maxDiffPixels option', async ({ runInlineTest }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
const BAD_PIXELS = 120;
|
|
|
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode, 'make sure default comparison fails').toBe(1);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
2022-03-04 10:17:31 +03:00
|
|
|
maxDiffPixels: ${BAD_PIXELS}
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
2022-03-04 10:17:31 +03:00
|
|
|
})).exitCode, 'make sure maxDiffPixels option is respected').toBe(0);
|
2022-02-28 23:25:59 +03:00
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-03-11 03:50:26 +03:00
|
|
|
...playwrightConfig({
|
2022-05-09 17:34:53 +03:00
|
|
|
expect: {
|
|
|
|
toHaveScreenshot: {
|
|
|
|
maxDiffPixels: BAD_PIXELS
|
|
|
|
}
|
|
|
|
},
|
2022-03-11 03:50:26 +03:00
|
|
|
projects: [
|
|
|
|
{
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 03:50:26 +03:00
|
|
|
},
|
|
|
|
],
|
|
|
|
}),
|
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
2022-03-04 10:17:31 +03:00
|
|
|
})).exitCode, 'make sure maxDiffPixels option in project config is respected').toBe(0);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
2022-06-22 04:01:25 +03:00
|
|
|
test('should not update screenshot that matches with maxDiffPixels option when -u is passed', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const BAD_PIXELS = 120;
|
|
|
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
|
|
|
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-06-22 04:01:25 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { maxDiffPixels: ${BAD_PIXELS} });
|
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
expect(result.output).not.toContain(`is re-generated, writing actual`);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-actual.png'))).toBe(false);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-expected.png'))).toBe(false);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-previous.png'))).toBe(false);
|
|
|
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'a-is-a-test', 'is-a-test-1-diff.png'))).toBe(false);
|
|
|
|
|
|
|
|
const data = fs.readFileSync(testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png'));
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(data, EXPECTED_SNAPSHOT)).toBe(null);
|
2022-06-22 04:01:25 +03:00
|
|
|
});
|
|
|
|
|
2022-03-05 05:27:04 +03:00
|
|
|
test('should satisfy both maxDiffPixelRatio and maxDiffPixels', async ({ runInlineTest }) => {
|
|
|
|
const BAD_RATIO = 0.25;
|
|
|
|
const BAD_COUNT = Math.floor(IMG_WIDTH * IMG_HEIGHT * BAD_RATIO);
|
|
|
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_COUNT);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-03-05 05:27:04 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-03-05 05:27:04 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode, 'make sure default comparison fails').toBe(1);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-03-05 05:27:04 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
2022-03-05 05:27:04 +03:00
|
|
|
maxDiffPixels: ${Math.floor(BAD_COUNT / 2)},
|
|
|
|
maxDiffPixelRatio: ${BAD_RATIO},
|
|
|
|
timeout: 2000,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode, 'make sure it fails when maxDiffPixels < actualBadPixels < maxDiffPixelRatio').toBe(1);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-03-05 05:27:04 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
2022-03-05 05:27:04 +03:00
|
|
|
maxDiffPixels: ${BAD_COUNT},
|
|
|
|
maxDiffPixelRatio: ${BAD_RATIO / 2},
|
|
|
|
timeout: 2000,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode, 'make sure it fails when maxDiffPixelRatio < actualBadPixels < maxDiffPixels').toBe(1);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-03-05 05:27:04 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
2022-03-05 05:27:04 +03:00
|
|
|
maxDiffPixels: ${BAD_COUNT},
|
|
|
|
maxDiffPixelRatio: ${BAD_RATIO},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode, 'make sure it passes when actualBadPixels < maxDiffPixelRatio && actualBadPixels < maxDiffPixels').toBe(0);
|
|
|
|
});
|
|
|
|
|
2022-03-04 10:17:31 +03:00
|
|
|
test('should respect maxDiffPixelRatio option', async ({ runInlineTest }) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
const BAD_RATIO = 0.25;
|
|
|
|
const BAD_PIXELS = IMG_WIDTH * IMG_HEIGHT * BAD_RATIO;
|
|
|
|
const EXPECTED_SNAPSHOT = paintBlackPixels(whiteImage, BAD_PIXELS);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode, 'make sure default comparison fails').toBe(1);
|
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', {
|
2022-03-04 10:17:31 +03:00
|
|
|
maxDiffPixelRatio: ${BAD_RATIO}
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
2022-03-04 10:17:31 +03:00
|
|
|
})).exitCode, 'make sure maxDiffPixelRatio option is respected').toBe(0);
|
2022-02-28 23:25:59 +03:00
|
|
|
|
|
|
|
expect((await runInlineTest({
|
2022-03-11 03:50:26 +03:00
|
|
|
...playwrightConfig({
|
2022-05-09 17:34:53 +03:00
|
|
|
expect: {
|
|
|
|
toHaveScreenshot: {
|
|
|
|
maxDiffPixelRatio: BAD_RATIO,
|
|
|
|
},
|
|
|
|
},
|
2022-03-11 03:50:26 +03:00
|
|
|
projects: [{
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 03:50:26 +03:00
|
|
|
}],
|
|
|
|
}),
|
|
|
|
'__screenshots__/a.spec.js/snapshot.png': EXPECTED_SNAPSHOT,
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
2022-03-04 10:17:31 +03:00
|
|
|
})).exitCode, 'make sure maxDiffPixels option in project config is respected').toBe(0);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
2022-03-05 05:27:04 +03:00
|
|
|
test('should throw for invalid maxDiffPixels values', async ({ runInlineTest }) => {
|
|
|
|
expect((await runInlineTest({
|
2022-04-14 02:13:30 +03:00
|
|
|
...playwrightConfig({}),
|
2022-03-05 05:27:04 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({
|
2022-03-05 05:27:04 +03:00
|
|
|
maxDiffPixels: -1,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode).toBe(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should throw for invalid maxDiffPixelRatio values', async ({ runInlineTest }) => {
|
|
|
|
expect((await runInlineTest({
|
2022-04-14 02:13:30 +03:00
|
|
|
...playwrightConfig({}),
|
2022-03-05 05:27:04 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot({
|
2022-03-05 05:27:04 +03:00
|
|
|
maxDiffPixelRatio: 12,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
})).exitCode).toBe(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2022-02-28 23:25:59 +03:00
|
|
|
test('should attach expected/actual and no diff when sizes are different', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-11-10 02:29:07 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
2022-03-11 03:50:26 +03:00
|
|
|
'__screenshots__/a.spec.js/snapshot.png': createImage(2, 2),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test.afterEach(async ({}, testInfo) => {
|
2022-02-28 23:25:59 +03:00
|
|
|
console.log('## ' + JSON.stringify(testInfo.attachments));
|
|
|
|
});
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png', { timeout: 2000 });
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
const outputText = stripAnsi(result.output);
|
|
|
|
expect(outputText).toContain('Expected an image 2px by 2px, received 1280px by 720px.');
|
|
|
|
const attachments = outputText.split('\n').filter(l => l.startsWith('## ')).map(l => l.substring(3)).map(l => JSON.parse(l))[0];
|
|
|
|
for (const attachment of attachments)
|
|
|
|
attachment.path = attachment.path.replace(/\\/g, '/').replace(/.*test-results\//, '');
|
|
|
|
expect(attachments).toEqual([
|
|
|
|
{
|
2022-03-11 19:46:13 +03:00
|
|
|
name: 'snapshot-expected.png',
|
2022-02-28 23:25:59 +03:00
|
|
|
contentType: 'image/png',
|
|
|
|
path: 'a-is-a-test/snapshot-expected.png'
|
|
|
|
},
|
|
|
|
{
|
2022-03-11 19:46:13 +03:00
|
|
|
name: 'snapshot-actual.png',
|
2022-02-28 23:25:59 +03:00
|
|
|
contentType: 'image/png',
|
|
|
|
path: 'a-is-a-test/snapshot-actual.png'
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should fail with missing expectations and retries', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-03-11 03:50:26 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
retries: 1,
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 03:50:26 +03:00
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.failed).toBe(1);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`A snapshot doesn't exist at ${snapshotOutputPath}, writing actual`);
|
2022-02-28 23:25:59 +03:00
|
|
|
const data = fs.readFileSync(snapshotOutputPath);
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(data, whiteImage)).toBe(null);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
test('should update expectations with retries', async ({ runInlineTest }, testInfo) => {
|
|
|
|
const result = await runInlineTest({
|
2022-03-11 03:50:26 +03:00
|
|
|
...playwrightConfig({
|
|
|
|
retries: 1,
|
2022-11-10 02:29:07 +03:00
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
2022-03-11 03:50:26 +03:00
|
|
|
}),
|
2022-02-28 23:25:59 +03:00
|
|
|
'a.spec.js': `
|
2022-03-11 03:50:26 +03:00
|
|
|
pwt.test('is a test', async ({ page }) => {
|
2022-04-14 23:22:42 +03:00
|
|
|
await expect(page).toHaveScreenshot('snapshot.png');
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
`
|
|
|
|
}, { 'update-snapshots': true });
|
|
|
|
|
|
|
|
expect(result.exitCode).toBe(0);
|
|
|
|
expect(result.passed).toBe(1);
|
2022-03-11 03:50:26 +03:00
|
|
|
const snapshotOutputPath = testInfo.outputPath('__screenshots__/a.spec.js/snapshot.png');
|
2022-11-29 23:51:15 +03:00
|
|
|
expect(result.output).toContain(`A snapshot doesn't exist at ${snapshotOutputPath}, writing actual`);
|
2022-02-28 23:25:59 +03:00
|
|
|
const data = fs.readFileSync(snapshotOutputPath);
|
2022-11-08 00:32:46 +03:00
|
|
|
expect(comparePNGs(data, whiteImage)).toBe(null);
|
2022-02-28 23:25:59 +03:00
|
|
|
});
|
|
|
|
|
feat: implement a new image comparison function (#19166)
This patch implements a new image comparison function, codenamed
"ssim-cie94". The goal of the new comparison function is to cancel out
browser non-determenistic rendering.
To use the new comparison function:
```ts
await expect(page).toHaveScreenshot({
comparator: 'ssim-cie94',
});
```
As of Nov 30, 2022, we identified the following sources of
non-determenistic rendering for Chromium:
- Anti-aliasing for certain shapes might be different due to the
way skia rasterizes certain shapes.
- Color blending might be different on `x86` and `aarch64`
architectures.
The new function employs a few heuristics to fight these
differences.
Consider two non-equal image pixels `(r1, g1, b1)` and `(r2, g2, b2)`:
1. If the [CIE94] metric is less then 1.0, then we consider these pixels
**EQUAL**. (The value `1.0` is the [just-noticeable difference] for
[CIE94].). Otherwise, proceed to next step.
1. If all the 8 neighbors of the first pixel match its color, or
if the 8 neighbors of the second pixel match its color, then these
pixels are **DIFFERENT**. (In case of anti-aliasing, some of the
direct neighbors have to be blended up or down.) Otherwise, proceed
to next step.
1. If SSIM in some locality around the different pixels is more than
0.99, then consider this pixels to be **EQUAL**. Otherwise, mark them
as **DIFFERENT**. (Local SSIM for anti-aliased pixels turns out to be
very close to 1.0).
[CIE94]: https://en.wikipedia.org/wiki/Color_difference#CIE94
[just-noticeable difference]:
https://en.wikipedia.org/wiki/Just-noticeable_difference
2022-12-03 02:22:05 +03:00
|
|
|
test('should respect comparator name', async ({ runInlineTest }) => {
|
|
|
|
const expected = fs.readFileSync(path.join(__dirname, '../image_tools/fixtures/should-match/tiny-antialiasing-sample/tiny-expected.png'));
|
|
|
|
const actualURL = pathToFileURL(path.join(__dirname, '../image_tools/fixtures/should-match/tiny-antialiasing-sample/tiny-actual.png'));
|
|
|
|
const result = await runInlineTest({
|
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
}),
|
|
|
|
'__screenshots__/a.spec.js/snapshot.png': expected,
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('should pass', async ({ page }) => {
|
|
|
|
await page.goto('${actualURL}');
|
|
|
|
await expect(page.locator('img')).toHaveScreenshot('snapshot.png', {
|
|
|
|
threshold: 0,
|
2022-12-14 20:58:19 +03:00
|
|
|
_comparator: 'ssim-cie94',
|
feat: implement a new image comparison function (#19166)
This patch implements a new image comparison function, codenamed
"ssim-cie94". The goal of the new comparison function is to cancel out
browser non-determenistic rendering.
To use the new comparison function:
```ts
await expect(page).toHaveScreenshot({
comparator: 'ssim-cie94',
});
```
As of Nov 30, 2022, we identified the following sources of
non-determenistic rendering for Chromium:
- Anti-aliasing for certain shapes might be different due to the
way skia rasterizes certain shapes.
- Color blending might be different on `x86` and `aarch64`
architectures.
The new function employs a few heuristics to fight these
differences.
Consider two non-equal image pixels `(r1, g1, b1)` and `(r2, g2, b2)`:
1. If the [CIE94] metric is less then 1.0, then we consider these pixels
**EQUAL**. (The value `1.0` is the [just-noticeable difference] for
[CIE94].). Otherwise, proceed to next step.
1. If all the 8 neighbors of the first pixel match its color, or
if the 8 neighbors of the second pixel match its color, then these
pixels are **DIFFERENT**. (In case of anti-aliasing, some of the
direct neighbors have to be blended up or down.) Otherwise, proceed
to next step.
1. If SSIM in some locality around the different pixels is more than
0.99, then consider this pixels to be **EQUAL**. Otherwise, mark them
as **DIFFERENT**. (Local SSIM for anti-aliased pixels turns out to be
very close to 1.0).
[CIE94]: https://en.wikipedia.org/wiki/Color_difference#CIE94
[just-noticeable difference]:
https://en.wikipedia.org/wiki/Just-noticeable_difference
2022-12-03 02:22:05 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
pwt.test('should fail', async ({ page }) => {
|
|
|
|
await page.goto('${actualURL}');
|
|
|
|
await expect(page.locator('img')).toHaveScreenshot('snapshot.png', {
|
|
|
|
threshold: 0,
|
2022-12-14 20:58:19 +03:00
|
|
|
_comparator: 'pixelmatch',
|
feat: implement a new image comparison function (#19166)
This patch implements a new image comparison function, codenamed
"ssim-cie94". The goal of the new comparison function is to cancel out
browser non-determenistic rendering.
To use the new comparison function:
```ts
await expect(page).toHaveScreenshot({
comparator: 'ssim-cie94',
});
```
As of Nov 30, 2022, we identified the following sources of
non-determenistic rendering for Chromium:
- Anti-aliasing for certain shapes might be different due to the
way skia rasterizes certain shapes.
- Color blending might be different on `x86` and `aarch64`
architectures.
The new function employs a few heuristics to fight these
differences.
Consider two non-equal image pixels `(r1, g1, b1)` and `(r2, g2, b2)`:
1. If the [CIE94] metric is less then 1.0, then we consider these pixels
**EQUAL**. (The value `1.0` is the [just-noticeable difference] for
[CIE94].). Otherwise, proceed to next step.
1. If all the 8 neighbors of the first pixel match its color, or
if the 8 neighbors of the second pixel match its color, then these
pixels are **DIFFERENT**. (In case of anti-aliasing, some of the
direct neighbors have to be blended up or down.) Otherwise, proceed
to next step.
1. If SSIM in some locality around the different pixels is more than
0.99, then consider this pixels to be **EQUAL**. Otherwise, mark them
as **DIFFERENT**. (Local SSIM for anti-aliased pixels turns out to be
very close to 1.0).
[CIE94]: https://en.wikipedia.org/wiki/Color_difference#CIE94
[just-noticeable difference]:
https://en.wikipedia.org/wiki/Just-noticeable_difference
2022-12-03 02:22:05 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.report.suites[0].specs[0].title).toBe('should pass');
|
|
|
|
expect(result.report.suites[0].specs[0].ok).toBe(true);
|
|
|
|
expect(result.report.suites[0].specs[1].title).toBe('should fail');
|
|
|
|
expect(result.report.suites[0].specs[1].ok).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should respect comparator in config', async ({ runInlineTest }) => {
|
|
|
|
const expected = fs.readFileSync(path.join(__dirname, '../image_tools/fixtures/should-match/tiny-antialiasing-sample/tiny-expected.png'));
|
|
|
|
const actualURL = pathToFileURL(path.join(__dirname, '../image_tools/fixtures/should-match/tiny-antialiasing-sample/tiny-actual.png'));
|
|
|
|
const result = await runInlineTest({
|
|
|
|
...playwrightConfig({
|
|
|
|
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
|
|
|
projects: [
|
|
|
|
{
|
|
|
|
name: 'should-pass',
|
|
|
|
expect: {
|
|
|
|
toHaveScreenshot: {
|
2022-12-14 20:58:19 +03:00
|
|
|
_comparator: 'ssim-cie94',
|
feat: implement a new image comparison function (#19166)
This patch implements a new image comparison function, codenamed
"ssim-cie94". The goal of the new comparison function is to cancel out
browser non-determenistic rendering.
To use the new comparison function:
```ts
await expect(page).toHaveScreenshot({
comparator: 'ssim-cie94',
});
```
As of Nov 30, 2022, we identified the following sources of
non-determenistic rendering for Chromium:
- Anti-aliasing for certain shapes might be different due to the
way skia rasterizes certain shapes.
- Color blending might be different on `x86` and `aarch64`
architectures.
The new function employs a few heuristics to fight these
differences.
Consider two non-equal image pixels `(r1, g1, b1)` and `(r2, g2, b2)`:
1. If the [CIE94] metric is less then 1.0, then we consider these pixels
**EQUAL**. (The value `1.0` is the [just-noticeable difference] for
[CIE94].). Otherwise, proceed to next step.
1. If all the 8 neighbors of the first pixel match its color, or
if the 8 neighbors of the second pixel match its color, then these
pixels are **DIFFERENT**. (In case of anti-aliasing, some of the
direct neighbors have to be blended up or down.) Otherwise, proceed
to next step.
1. If SSIM in some locality around the different pixels is more than
0.99, then consider this pixels to be **EQUAL**. Otherwise, mark them
as **DIFFERENT**. (Local SSIM for anti-aliased pixels turns out to be
very close to 1.0).
[CIE94]: https://en.wikipedia.org/wiki/Color_difference#CIE94
[just-noticeable difference]:
https://en.wikipedia.org/wiki/Just-noticeable_difference
2022-12-03 02:22:05 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'should-fail',
|
|
|
|
expect: {
|
|
|
|
toHaveScreenshot: {
|
2022-12-14 20:58:19 +03:00
|
|
|
_comparator: 'pixelmatch',
|
feat: implement a new image comparison function (#19166)
This patch implements a new image comparison function, codenamed
"ssim-cie94". The goal of the new comparison function is to cancel out
browser non-determenistic rendering.
To use the new comparison function:
```ts
await expect(page).toHaveScreenshot({
comparator: 'ssim-cie94',
});
```
As of Nov 30, 2022, we identified the following sources of
non-determenistic rendering for Chromium:
- Anti-aliasing for certain shapes might be different due to the
way skia rasterizes certain shapes.
- Color blending might be different on `x86` and `aarch64`
architectures.
The new function employs a few heuristics to fight these
differences.
Consider two non-equal image pixels `(r1, g1, b1)` and `(r2, g2, b2)`:
1. If the [CIE94] metric is less then 1.0, then we consider these pixels
**EQUAL**. (The value `1.0` is the [just-noticeable difference] for
[CIE94].). Otherwise, proceed to next step.
1. If all the 8 neighbors of the first pixel match its color, or
if the 8 neighbors of the second pixel match its color, then these
pixels are **DIFFERENT**. (In case of anti-aliasing, some of the
direct neighbors have to be blended up or down.) Otherwise, proceed
to next step.
1. If SSIM in some locality around the different pixels is more than
0.99, then consider this pixels to be **EQUAL**. Otherwise, mark them
as **DIFFERENT**. (Local SSIM for anti-aliased pixels turns out to be
very close to 1.0).
[CIE94]: https://en.wikipedia.org/wiki/Color_difference#CIE94
[just-noticeable difference]:
https://en.wikipedia.org/wiki/Just-noticeable_difference
2022-12-03 02:22:05 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}),
|
|
|
|
'__screenshots__/a.spec.js/snapshot.png': expected,
|
|
|
|
'a.spec.js': `
|
|
|
|
pwt.test('test', async ({ page }) => {
|
|
|
|
await page.goto('${actualURL}');
|
|
|
|
await expect(page.locator('img')).toHaveScreenshot('snapshot.png', { threshold: 0, });
|
|
|
|
});
|
|
|
|
`
|
|
|
|
});
|
|
|
|
expect(result.exitCode).toBe(1);
|
|
|
|
expect(result.report.suites[0].specs[0].tests[0].projectName).toBe('should-pass');
|
|
|
|
expect(result.report.suites[0].specs[0].tests[0].status).toBe('expected');
|
|
|
|
expect(result.report.suites[0].specs[0].tests[1].projectName).toBe('should-fail');
|
|
|
|
expect(result.report.suites[0].specs[0].tests[1].status).toBe('unexpected');
|
|
|
|
});
|
|
|
|
|
2022-03-11 03:50:26 +03:00
|
|
|
function playwrightConfig(obj: any) {
|
|
|
|
return {
|
|
|
|
'playwright.config.js': `
|
|
|
|
module.exports = ${JSON.stringify(obj, null, 2)}
|
|
|
|
`,
|
|
|
|
};
|
|
|
|
}
|