@augment-vir/test 31.64.0 → 31.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/augments/test-playwright.d.ts +7 -5
- package/dist/augments/test-playwright.js +5 -3
- package/dist/augments/test-web.d.ts +2 -3
- package/dist/augments/test-web.js +3 -4
- package/dist/test-playwright/{screenshot.d.ts → playwright-screenshot.d.ts} +1 -1
- package/dist/test-playwright/{screenshot.js → playwright-screenshot.js} +2 -2
- package/dist/test-web/web-screenshot.d.ts +7 -0
- package/dist/test-web/web-screenshot.js +34 -0
- package/package.json +4 -4
- package/dist/test-playwright/compare-images.d.ts +0 -71
- package/dist/test-playwright/compare-images.js +0 -87
- package/dist/test-web/test-screenshot.d.ts +0 -1
- package/dist/test-web/test-screenshot.js +0 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RuntimeEnvError } from '@augment-vir/core';
|
|
2
2
|
export { type MenuOptionOptions } from '../test-playwright/get-option.js';
|
|
3
3
|
export { type NavOptions } from '../test-playwright/nav.js';
|
|
4
|
-
export { type LocatorScreenshotOptions, type SaveScreenshotOptions, type TakeScreenshotOptions, } from '../test-playwright/screenshot.js';
|
|
4
|
+
export { type LocatorScreenshotOptions, type SaveScreenshotOptions, type TakeScreenshotOptions, } from '../test-playwright/playwright-screenshot.js';
|
|
5
5
|
declare function importPlaywrightTestApi(this: void): Promise<RuntimeEnvError | {
|
|
6
6
|
navigation: {
|
|
7
7
|
/** Navigate to a URL in Playwright via given paths. */
|
|
@@ -31,17 +31,19 @@ declare function importPlaywrightTestApi(this: void): Promise<RuntimeEnvError |
|
|
|
31
31
|
/**
|
|
32
32
|
* Similar to Playwright's `expect().toHaveScreenshot` but allows images to have
|
|
33
33
|
* different sizes and has default comparison threshold options that are wide enough to
|
|
34
|
-
* allow testing between different operating systems without failure
|
|
34
|
+
* allow testing between different operating systems without failure.
|
|
35
|
+
*
|
|
36
|
+
* Update screenshots with `--update`.
|
|
35
37
|
*/
|
|
36
|
-
expectScreenshot: typeof import("../test-playwright/screenshot.js").
|
|
38
|
+
expectScreenshot: typeof import("../test-playwright/playwright-screenshot.js").expectPlaywrightScreenshot;
|
|
37
39
|
/** Get the path to save the given screenshot file name to. */
|
|
38
|
-
getScreenshotPath: typeof import("../test-playwright/screenshot.js").getScreenshotPath;
|
|
40
|
+
getScreenshotPath: typeof import("../test-playwright/playwright-screenshot.js").getScreenshotPath;
|
|
39
41
|
/**
|
|
40
42
|
* Take and immediately save a screenshot.
|
|
41
43
|
*
|
|
42
44
|
* @returns The path that the screenshot was saved to.
|
|
43
45
|
*/
|
|
44
|
-
takeScreenshot: typeof import("../test-playwright/screenshot.js").takeScreenshot;
|
|
46
|
+
takeScreenshot: typeof import("../test-playwright/playwright-screenshot.js").takeScreenshot;
|
|
45
47
|
};
|
|
46
48
|
}>;
|
|
47
49
|
/**
|
|
@@ -7,7 +7,7 @@ async function importPlaywrightTestApi() {
|
|
|
7
7
|
const { enterTextByLabel } = await import('../test-playwright/enter-text.js');
|
|
8
8
|
const { expectAllVisible } = await import('../test-playwright/all-visible.js');
|
|
9
9
|
const { getMenuOption } = await import('../test-playwright/get-option.js');
|
|
10
|
-
const { getScreenshotPath, takeScreenshot,
|
|
10
|
+
const { getScreenshotPath, takeScreenshot, expectPlaywrightScreenshot } = await import('../test-playwright/playwright-screenshot.js');
|
|
11
11
|
const { handleNewPageOrDownload } = await import('../test-playwright/new-page-or-download.js');
|
|
12
12
|
const { navigateTo, extractNavUrl } = await import('../test-playwright/nav.js');
|
|
13
13
|
const { readLocalStorage } = await import('../test-playwright/local-storage.js');
|
|
@@ -40,9 +40,11 @@ async function importPlaywrightTestApi() {
|
|
|
40
40
|
/**
|
|
41
41
|
* Similar to Playwright's `expect().toHaveScreenshot` but allows images to have
|
|
42
42
|
* different sizes and has default comparison threshold options that are wide enough to
|
|
43
|
-
* allow testing between different operating systems without failure
|
|
43
|
+
* allow testing between different operating systems without failure.
|
|
44
|
+
*
|
|
45
|
+
* Update screenshots with `--update`.
|
|
44
46
|
*/
|
|
45
|
-
expectScreenshot,
|
|
47
|
+
expectScreenshot: expectPlaywrightScreenshot,
|
|
46
48
|
/** Get the path to save the given screenshot file name to. */
|
|
47
49
|
getScreenshotPath,
|
|
48
50
|
/**
|
|
@@ -17,10 +17,9 @@ declare function importWebTestApi(this: void): Promise<RuntimeEnvError | {
|
|
|
17
17
|
/**
|
|
18
18
|
* Test a screenshot against an already established screenshot.
|
|
19
19
|
*
|
|
20
|
-
* To update screenshots, run the test command with `--update
|
|
21
|
-
* `--update-visual-baseline`.
|
|
20
|
+
* To update screenshots, run the test command with `--update`.
|
|
22
21
|
*/
|
|
23
|
-
|
|
22
|
+
assertScreenshot: typeof import("../test-web/web-screenshot.js").assertWebScreenshot;
|
|
24
23
|
/**
|
|
25
24
|
* Renders a string or TemplateResult and puts it in the DOM via a fixtureWrapper.
|
|
26
25
|
*
|
|
@@ -9,7 +9,7 @@ async function importWebTestApi() {
|
|
|
9
9
|
const { fixtureCleanup, fixture } = await import('@open-wc/testing-helpers');
|
|
10
10
|
const { renderElement } = await import('../test-web/render-element.js');
|
|
11
11
|
const { elementCases } = await import('../test-web/element-cases.js');
|
|
12
|
-
const {
|
|
12
|
+
const { assertWebScreenshot } = await import('../test-web/web-screenshot.js');
|
|
13
13
|
return {
|
|
14
14
|
/**
|
|
15
15
|
* Cleans up all rendered test HTML by removing the actual wrapper nodes. Common use case is
|
|
@@ -27,10 +27,9 @@ async function importWebTestApi() {
|
|
|
27
27
|
/**
|
|
28
28
|
* Test a screenshot against an already established screenshot.
|
|
29
29
|
*
|
|
30
|
-
* To update screenshots, run the test command with `--update
|
|
31
|
-
* `--update-visual-baseline`.
|
|
30
|
+
* To update screenshots, run the test command with `--update`.
|
|
32
31
|
*/
|
|
33
|
-
|
|
32
|
+
assertScreenshot: assertWebScreenshot,
|
|
34
33
|
/**
|
|
35
34
|
* Renders a string or TemplateResult and puts it in the DOM via a fixtureWrapper.
|
|
36
35
|
*
|
|
@@ -83,5 +83,5 @@ export declare function takeScreenshot(testContext: Readonly<UniversalTestContex
|
|
|
83
83
|
*
|
|
84
84
|
* @category Internal
|
|
85
85
|
*/
|
|
86
|
-
export declare function
|
|
86
|
+
export declare function expectPlaywrightScreenshot(testContext: Readonly<UniversalTestContext>, options: Readonly<SaveScreenshotOptions>): Promise<void>;
|
|
87
87
|
export {};
|
|
@@ -2,11 +2,11 @@ import { assert } from '@augment-vir/assert';
|
|
|
2
2
|
import { addSuffix, log } from '@augment-vir/common';
|
|
3
3
|
import { writeFileAndDir } from '@augment-vir/node';
|
|
4
4
|
import { expect } from '@playwright/test';
|
|
5
|
+
import { compareImages, defaultImageComparisonOptions, encodePng, } from '@virmator/test/dist/web-screenshot-plugin/compare-images.js';
|
|
5
6
|
import { existsSync } from 'node:fs';
|
|
6
7
|
import { readFile } from 'node:fs/promises';
|
|
7
8
|
import { relative } from 'node:path';
|
|
8
9
|
import { assertTestContext, assertWrapTestContext, TestEnv, } from '../augments/universal-testing-suite/universal-test-context.js';
|
|
9
|
-
import { compareImages, defaultImageComparisonOptions, encodePng } from './compare-images.js';
|
|
10
10
|
/** This is used for type extraction because Playwright does not export the types we need. */
|
|
11
11
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
12
12
|
function extractScreenshotMethod() {
|
|
@@ -76,7 +76,7 @@ export async function takeScreenshot(testContext, options) {
|
|
|
76
76
|
*
|
|
77
77
|
* @category Internal
|
|
78
78
|
*/
|
|
79
|
-
export async function
|
|
79
|
+
export async function expectPlaywrightScreenshot(testContext, options) {
|
|
80
80
|
assertTestContext(testContext, TestEnv.Playwright);
|
|
81
81
|
const currentScreenshotBuffer = await takeScreenshotBuffer(testContext, options);
|
|
82
82
|
const screenshotFilePath = getScreenshotPath(testContext, options.screenshotBaseName);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
|
|
2
|
+
import { type CompareScreenshotCommandPayload } from '@virmator/test/dist/web-screenshot-plugin/screenshot-payload.js';
|
|
3
|
+
import { type UniversalTestContext } from '../augments/universal-testing-suite/universal-test-context.js';
|
|
4
|
+
export declare function assertWebScreenshot(element: Element, screenshotNameOrTestContext: string | UniversalTestContext, options?: Readonly<PartialWithUndefined<SelectFrom<CompareScreenshotCommandPayload, {
|
|
5
|
+
maxDiffPixelRatio: true;
|
|
6
|
+
threshold: true;
|
|
7
|
+
}>>>): Promise<void>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getOrSet, randomString, } from '@augment-vir/common';
|
|
2
|
+
import { globalElementStoreKey, ScreenshotCommand, } from '@virmator/test/dist/web-screenshot-plugin/screenshot-payload.js';
|
|
3
|
+
import { executeServerCommand } from '@web/test-runner-commands';
|
|
4
|
+
import { extractTestNameAsDir, } from '../augments/universal-testing-suite/universal-test-context.js';
|
|
5
|
+
export async function assertWebScreenshot(element, screenshotNameOrTestContext, options) {
|
|
6
|
+
if (!element.isConnected) {
|
|
7
|
+
throw new Error('Element must be connected to the DOM.');
|
|
8
|
+
}
|
|
9
|
+
else if (element.ownerDocument !== document) {
|
|
10
|
+
throw new Error('Element must belong to the same document the tests are run in.');
|
|
11
|
+
}
|
|
12
|
+
const elementKey = randomString();
|
|
13
|
+
getOrSet(globalThis, globalElementStoreKey, () => {
|
|
14
|
+
return {};
|
|
15
|
+
})[elementKey] = element;
|
|
16
|
+
const screenshotName = typeof screenshotNameOrTestContext === 'string'
|
|
17
|
+
? screenshotNameOrTestContext
|
|
18
|
+
: extractTestNameAsDir(screenshotNameOrTestContext);
|
|
19
|
+
const payload = {
|
|
20
|
+
...options,
|
|
21
|
+
elementKey,
|
|
22
|
+
screenshotFileName: screenshotName,
|
|
23
|
+
};
|
|
24
|
+
const result = await executeServerCommand(ScreenshotCommand.CompareScreenshot, payload);
|
|
25
|
+
if (result.updated) {
|
|
26
|
+
/** Ignore updates. */
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
else if (!result.passed) {
|
|
30
|
+
throw new Error(typeof screenshotNameOrTestContext === 'string'
|
|
31
|
+
? `Screenshot comparison failed for '${screenshotNameOrTestContext}'`
|
|
32
|
+
: 'Screenshot comparison failed.');
|
|
33
|
+
}
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@augment-vir/test",
|
|
3
|
-
"version": "31.64.
|
|
3
|
+
"version": "31.64.1",
|
|
4
4
|
"description": "A universal testing suite that works with Mocha style test runners _and_ Node.js's built-in test runner.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"test",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"test:web": "virmator test --no-deps web 'src/test-web/**/*.test.ts' 'src/augments/universal-testing-suite/**/*.test.ts'"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@augment-vir/assert": "^31.64.
|
|
48
|
-
"@augment-vir/common": "^31.64.
|
|
47
|
+
"@augment-vir/assert": "^31.64.1",
|
|
48
|
+
"@augment-vir/common": "^31.64.1",
|
|
49
49
|
"@date-vir/duration": "^8.1.1",
|
|
50
|
-
"@virmator/test": "^14.
|
|
50
|
+
"@virmator/test": "^14.6.1",
|
|
51
51
|
"type-fest": "^5.4.4"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { Dimensions } from '@augment-vir/common';
|
|
2
|
-
import { PNG } from 'pngjs';
|
|
3
|
-
/**
|
|
4
|
-
* Options for image comparison thresholds.
|
|
5
|
-
*
|
|
6
|
-
* @category Internal
|
|
7
|
-
*/
|
|
8
|
-
export type ImageComparisonOptions = {
|
|
9
|
-
/**
|
|
10
|
-
* Per-pixel color threshold for `pixelmatch` (0–1). Smaller values make comparison more
|
|
11
|
-
* sensitive.
|
|
12
|
-
*/
|
|
13
|
-
threshold: number;
|
|
14
|
-
/** Maximum ratio of differing pixels allowed before the comparison is considered a failure. */
|
|
15
|
-
maxDiffPixelRatio: number;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Default image comparison options used in {@link compareImages}.
|
|
19
|
-
*
|
|
20
|
-
* @category Internal
|
|
21
|
-
*/
|
|
22
|
-
export declare const defaultImageComparisonOptions: Readonly<ImageComparisonOptions>;
|
|
23
|
-
/**
|
|
24
|
-
* The result of comparing two images via {@link compareImages}.
|
|
25
|
-
*
|
|
26
|
-
* @category Internal
|
|
27
|
-
*/
|
|
28
|
-
export type ImageComparisonResult = {
|
|
29
|
-
/** Whether the images match within the allowed diff ratio. */
|
|
30
|
-
passed: boolean;
|
|
31
|
-
/** The number of differing pixels. */
|
|
32
|
-
diffPixelCount: number;
|
|
33
|
-
/** Total pixel count of the (padded) comparison canvas. */
|
|
34
|
-
totalPixels: number;
|
|
35
|
-
/** The ratio of differing pixels to total pixels. */
|
|
36
|
-
diffRatio: number;
|
|
37
|
-
/** The dimensions of the comparison canvas. */
|
|
38
|
-
dimensions: Readonly<Dimensions>;
|
|
39
|
-
/** PNG data for the base image (padded to the comparison canvas). */
|
|
40
|
-
basePng: PNG;
|
|
41
|
-
/** PNG data for the current image (padded to the comparison canvas). */
|
|
42
|
-
currentPng: PNG;
|
|
43
|
-
/** PNG data for the visual diff output. */
|
|
44
|
-
diffPng: PNG;
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Pads both images to the same canvas size (max width/height of the two) without scaling, then
|
|
48
|
-
* returns the decoded PNGs and the shared dimensions.
|
|
49
|
-
*
|
|
50
|
-
* @category Internal
|
|
51
|
-
*/
|
|
52
|
-
export declare function padToSameCanvas(aBuf: Buffer, bBuf: Buffer): Promise<{
|
|
53
|
-
aPng: import("pngjs").PNGWithMetadata;
|
|
54
|
-
bPng: import("pngjs").PNGWithMetadata;
|
|
55
|
-
dimensions: Readonly<Dimensions>;
|
|
56
|
-
}>;
|
|
57
|
-
/**
|
|
58
|
-
* Compare two PNG image buffers pixel-by-pixel. The images may have different dimensions — they
|
|
59
|
-
* will be padded to the same canvas size before comparison.
|
|
60
|
-
*
|
|
61
|
-
* This function is fully Playwright-agnostic and can be used in any Node.js context.
|
|
62
|
-
*
|
|
63
|
-
* @category Internal
|
|
64
|
-
*/
|
|
65
|
-
export declare function compareImages(baseImageBuffer: Buffer, currentImageBuffer: Buffer, options?: Readonly<ImageComparisonOptions>): Promise<ImageComparisonResult>;
|
|
66
|
-
/**
|
|
67
|
-
* Encode a {@link PNG} instance to a `Buffer`.
|
|
68
|
-
*
|
|
69
|
-
* @category Internal
|
|
70
|
-
*/
|
|
71
|
-
export declare function encodePng(png: PNG): Buffer;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import pixelmatch from 'pixelmatch';
|
|
2
|
-
import { PNG } from 'pngjs';
|
|
3
|
-
import sharp from 'sharp';
|
|
4
|
-
/**
|
|
5
|
-
* Default image comparison options used in {@link compareImages}.
|
|
6
|
-
*
|
|
7
|
-
* @category Internal
|
|
8
|
-
*/
|
|
9
|
-
export const defaultImageComparisonOptions = {
|
|
10
|
-
threshold: 0.1,
|
|
11
|
-
maxDiffPixelRatio: 0.08,
|
|
12
|
-
};
|
|
13
|
-
async function padImage(image, { height, width }) {
|
|
14
|
-
return await sharp({
|
|
15
|
-
create: { width, height, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } },
|
|
16
|
-
})
|
|
17
|
-
/** Top-left align. */
|
|
18
|
-
.composite([{ input: image, left: 0, top: 0 }])
|
|
19
|
-
.png()
|
|
20
|
-
.toBuffer();
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Pads both images to the same canvas size (max width/height of the two) without scaling, then
|
|
24
|
-
* returns the decoded PNGs and the shared dimensions.
|
|
25
|
-
*
|
|
26
|
-
* @category Internal
|
|
27
|
-
*/
|
|
28
|
-
export async function padToSameCanvas(aBuf, bBuf) {
|
|
29
|
-
const [aMeta, bMeta,] = await Promise.all([
|
|
30
|
-
sharp(aBuf).metadata(),
|
|
31
|
-
sharp(bBuf).metadata(),
|
|
32
|
-
]);
|
|
33
|
-
if (!aMeta.width || !aMeta.height || !bMeta.width || !bMeta.height) {
|
|
34
|
-
throw new Error('Unable to read image dimensions.');
|
|
35
|
-
}
|
|
36
|
-
const dimensions = {
|
|
37
|
-
width: Math.max(aMeta.width, bMeta.width),
|
|
38
|
-
height: Math.max(aMeta.height, bMeta.height),
|
|
39
|
-
};
|
|
40
|
-
const [aPadded, bPadded,] = await Promise.all([
|
|
41
|
-
padImage(aBuf, dimensions),
|
|
42
|
-
padImage(bBuf, dimensions),
|
|
43
|
-
]);
|
|
44
|
-
const aPng = PNG.sync.read(aPadded);
|
|
45
|
-
const bPng = PNG.sync.read(bPadded);
|
|
46
|
-
return {
|
|
47
|
-
aPng,
|
|
48
|
-
bPng,
|
|
49
|
-
dimensions,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Compare two PNG image buffers pixel-by-pixel. The images may have different dimensions — they
|
|
54
|
-
* will be padded to the same canvas size before comparison.
|
|
55
|
-
*
|
|
56
|
-
* This function is fully Playwright-agnostic and can be used in any Node.js context.
|
|
57
|
-
*
|
|
58
|
-
* @category Internal
|
|
59
|
-
*/
|
|
60
|
-
export async function compareImages(baseImageBuffer, currentImageBuffer, options = defaultImageComparisonOptions) {
|
|
61
|
-
const { aPng: basePng, bPng: currentPng, dimensions, } = await padToSameCanvas(baseImageBuffer, currentImageBuffer);
|
|
62
|
-
const diffPng = new PNG(dimensions);
|
|
63
|
-
const diffPixelCount = pixelmatch(basePng.data, currentPng.data, diffPng.data, dimensions.width, dimensions.height, {
|
|
64
|
-
threshold: options.threshold,
|
|
65
|
-
});
|
|
66
|
-
const totalPixels = dimensions.width * dimensions.height;
|
|
67
|
-
const diffRatio = diffPixelCount / totalPixels;
|
|
68
|
-
const passed = diffRatio <= options.maxDiffPixelRatio;
|
|
69
|
-
return {
|
|
70
|
-
passed,
|
|
71
|
-
diffPixelCount,
|
|
72
|
-
totalPixels,
|
|
73
|
-
diffRatio,
|
|
74
|
-
dimensions,
|
|
75
|
-
basePng,
|
|
76
|
-
currentPng,
|
|
77
|
-
diffPng,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Encode a {@link PNG} instance to a `Buffer`.
|
|
82
|
-
*
|
|
83
|
-
* @category Internal
|
|
84
|
-
*/
|
|
85
|
-
export function encodePng(png) {
|
|
86
|
-
return PNG.sync.write(png);
|
|
87
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function testScreenshot(element: Node, screenshotName: string): Promise<void>;
|