vitest-plugin-vis 1.2.0 → 1.3.0
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/esm/client/expect/augment.d.ts +8 -0
- package/esm/client/expect/augment.d.ts.map +1 -0
- package/esm/client/expect/augment.js +1 -0
- package/esm/client/expect/extend.d.ts +1 -7
- package/esm/client/expect/extend.d.ts.map +1 -1
- package/esm/client/expect/extend.js +1 -0
- package/esm/client/expect/to_match_image_snapshot.d.ts.map +1 -1
- package/esm/client/expect/to_match_image_snapshot.js +3 -2
- package/esm/client/expect/to_match_image_snapshot.types.d.ts +5 -0
- package/esm/client/expect/to_match_image_snapshot.types.d.ts.map +1 -1
- package/esm/client/match_image_snapshot.d.ts +4 -1
- package/esm/client/match_image_snapshot.d.ts.map +1 -1
- package/esm/client/match_image_snapshot.js +42 -31
- package/esm/client/match_image_snapshot.logic.js +1 -1
- package/esm/client/page/augment.d.ts +6 -0
- package/esm/client/page/augment.d.ts.map +1 -0
- package/esm/client/page/augment.js +1 -0
- package/esm/client/page/extend.d.ts +1 -5
- package/esm/client/page/extend.d.ts.map +1 -1
- package/esm/client/page/extend.js +1 -0
- package/esm/client/selector.d.ts +0 -2
- package/esm/client/selector.d.ts.map +1 -1
- package/esm/client/selector.js +5 -12
- package/esm/commands.d.ts +2 -0
- package/esm/commands.d.ts.map +1 -1
- package/esm/commands.js +2 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +2 -0
- package/esm/presets/auto.d.ts +2 -1
- package/esm/presets/auto.d.ts.map +1 -1
- package/esm/presets/auto.js +2 -0
- package/esm/presets/manual.d.ts +2 -1
- package/esm/presets/manual.d.ts.map +1 -1
- package/esm/presets/manual.js +2 -0
- package/esm/server/vis_context.logic.d.ts +1 -1
- package/esm/server/vis_context.logic.d.ts.map +1 -1
- package/esm/server/vis_context.logic.js +3 -3
- package/package.json +1 -1
- package/readme.md +18 -0
- package/src/client/expect/augment.ts +8 -0
- package/src/client/expect/extend.ts +1 -8
- package/src/client/expect/to_match_image_snapshot.ts +3 -2
- package/src/client/expect/to_match_image_snapshot.types.ts +7 -1
- package/src/client/match_image_snapshot.logic.ts +1 -1
- package/src/client/match_image_snapshot.ts +67 -44
- package/src/client/page/augment.ts +5 -0
- package/src/client/page/extend.ts +2 -5
- package/src/client/selector.ts +0 -13
- package/src/commands.ts +2 -0
- package/src/index.ts +3 -0
- package/src/presets/auto.ts +2 -0
- package/src/presets/manual.ts +2 -0
- package/src/server/vis_context.logic.ts +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"augment.d.ts","sourceRoot":"","sources":["../../../src/client/expect/augment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AAE9E,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,IAAI,CAAC;QAEd,UAAU,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,oBAAoB;SAAG;KACxD;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../../src/client/expect/extend.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../../src/client/expect/extend.ts"],"names":[],"mappings":"AAEA,OAAO,cAAc,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to_match_image_snapshot.d.ts","sourceRoot":"","sources":["../../../src/client/expect/to_match_image_snapshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"to_match_image_snapshot.d.ts","sourceRoot":"","sources":["../../../src/client/expect/to_match_image_snapshot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAI5D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAA;AAErF,wBAAgB,oBAAoB;AACnC;;;GAGG;AACH,OAAO,EAAE,GAAG,EACZ,OAAO,CAAC,EAAE,2BAA2B,GAAG,SAAS,GAC/C,sBAAsB,CAcxB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { commands } from '@vitest/browser/context';
|
|
1
2
|
import { ctx } from "../ctx.js";
|
|
2
|
-
import {
|
|
3
|
+
import { imageSnapshotMatcher } from "../match_image_snapshot.js";
|
|
3
4
|
import { success } from "./expectation_result.js";
|
|
4
5
|
export function toMatchImageSnapshot(
|
|
5
6
|
/**
|
|
@@ -15,5 +16,5 @@ subject, options) {
|
|
|
15
16
|
throw new Error('`toMatchImageSnapshot()` cannot be called in a concurrent test because ' +
|
|
16
17
|
"concurrent tests run at the same time in the same iframe and affect each other's environment. ");
|
|
17
18
|
}
|
|
18
|
-
return
|
|
19
|
+
return imageSnapshotMatcher(commands)(test, subject, options).then(() => success);
|
|
19
20
|
}
|
|
@@ -3,5 +3,10 @@ export interface ImageSnapshotMatcher {
|
|
|
3
3
|
toMatchImageSnapshot(options?: ToMatchImageSnapshotOptions | undefined): Promise<void>;
|
|
4
4
|
}
|
|
5
5
|
export interface ToMatchImageSnapshotOptions extends ImageSnapshotTimeoutOptions, ImageSnapshotIdOptions, ImageSnapshotCompareOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Expect the matcher to fail.
|
|
8
|
+
* If it passes, it will throw an error with details.
|
|
9
|
+
*/
|
|
10
|
+
expectToFail?: boolean | undefined;
|
|
6
11
|
}
|
|
7
12
|
//# sourceMappingURL=to_match_image_snapshot.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to_match_image_snapshot.types.d.ts","sourceRoot":"","sources":["../../../src/client/expect/to_match_image_snapshot.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,oBAAoB;IACpC,oBAAoB,CAAC,OAAO,CAAC,EAAE,2BAA2B,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtF;AAED,MAAM,WAAW,2BAChB,SAAQ,2BAA2B,EAClC,sBAAsB,EACtB,2BAA2B;
|
|
1
|
+
{"version":3,"file":"to_match_image_snapshot.types.d.ts","sourceRoot":"","sources":["../../../src/client/expect/to_match_image_snapshot.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,oBAAoB;IACpC,oBAAoB,CAAC,OAAO,CAAC,EAAE,2BAA2B,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtF;AAED,MAAM,WAAW,2BAChB,SAAQ,2BAA2B,EAClC,sBAAsB,EACtB,2BAA2B;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAClC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Task } from 'vitest';
|
|
2
|
+
import type { ImageSnapshotNextIndexCommand } from '../commands.ts';
|
|
3
|
+
import type { PrepareImageSnapshotComparisonCommand } from '../server/commands/prepare_image_snapshot_comparison.ts';
|
|
4
|
+
import type { WriteImageSnapshotCommand } from '../server/commands/write_image_snapshot.ts';
|
|
2
5
|
import type { ToMatchImageSnapshotOptions } from './expect/to_match_image_snapshot.types.ts';
|
|
3
|
-
export declare function
|
|
6
|
+
export declare function imageSnapshotMatcher(commands: PrepareImageSnapshotComparisonCommand & WriteImageSnapshotCommand & ImageSnapshotNextIndexCommand): (test: Task, subject: any, options?: ToMatchImageSnapshotOptions) => Promise<void>;
|
|
4
7
|
/**
|
|
5
8
|
* @deprecated internalized. Use `matchImageSnapshot` directly instead.
|
|
6
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match_image_snapshot.d.ts","sourceRoot":"","sources":["../../src/client/match_image_snapshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"match_image_snapshot.d.ts","sourceRoot":"","sources":["../../src/client/match_image_snapshot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAClC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,yDAAyD,CAAA;AACpH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAA;AAI3F,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAA;AAO5F,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,qCAAqC,GAAG,yBAAyB,GAAG,6BAA6B,UAE5D,IAAI,WAAW,GAAG,YAAY,2BAA2B,mBA8DxG;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,GAAG,OAOrD"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { commands } from '@vitest/browser/context';
|
|
2
1
|
import dedent from 'dedent';
|
|
3
2
|
import { resolve } from 'pathe';
|
|
4
3
|
import { isBase64String } from "../shared/base64.js";
|
|
@@ -9,37 +8,49 @@ import { prettifyOptions } from "./match_image_snapshot.logic.js";
|
|
|
9
8
|
import { convertElementToCssSelector } from "./selector.js";
|
|
10
9
|
import { toTaskId } from "./task_id.js";
|
|
11
10
|
import { server } from "./vitest_browser_context_proxy.js";
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
await writeSnapshot(info.diffPath, diffImage);
|
|
30
|
-
throw new Error(dedent `Snapshot \`${taskId}\` mismatched
|
|
11
|
+
export function imageSnapshotMatcher(commands) {
|
|
12
|
+
return async function matchImageSnapshot(test, subject, options) {
|
|
13
|
+
const taskId = toTaskId(test);
|
|
14
|
+
const info = await commands.prepareImageSnapshotComparison(taskId, parseImageSnapshotSubject(subject), options?.customizeSnapshotId ? await parseImageSnapshotOptions(commands, taskId, options) : options);
|
|
15
|
+
if (!info)
|
|
16
|
+
return;
|
|
17
|
+
const baselineImage = await toImageData(info.baseline);
|
|
18
|
+
const resultImage = await toImageData(info.result);
|
|
19
|
+
const [baselineAlignedImage, resultAlignedImage] = alignImagesToSameSize(baselineImage, resultImage);
|
|
20
|
+
const { width, height } = baselineAlignedImage;
|
|
21
|
+
const diffImage = new ImageData(width, height);
|
|
22
|
+
const { pass, diffAmount } = compareImage(baselineAlignedImage.data, resultAlignedImage.data, diffImage.data, width, height, options);
|
|
23
|
+
if (pass) {
|
|
24
|
+
if (options?.expectToFail) {
|
|
25
|
+
throw new Error(dedent `Snapshot \`${taskId}\` matched but expected to fail.
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`
|
|
35
|
-
: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`
|
|
36
|
-
: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`}
|
|
27
|
+
Options: ${prettifyOptions(options)}
|
|
28
|
+
DiffAmount: ${options.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
Expected: ${resolve(info.projectRoot, info.baselinePath)}
|
|
31
|
+
Actual: ${resolve(info.projectRoot, info.resultPath)}`);
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (server.config.snapshotOptions.updateSnapshot === 'all') {
|
|
36
|
+
await writeSnapshot(commands, info.baselinePath, resultImage);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await writeSnapshot(commands, info.diffPath, diffImage);
|
|
40
|
+
throw new Error(dedent `Snapshot \`${taskId}\` mismatched
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
${options?.failureThreshold
|
|
43
|
+
? options?.failureThresholdType === 'percent'
|
|
44
|
+
? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`
|
|
45
|
+
: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`
|
|
46
|
+
: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`}
|
|
47
|
+
|
|
48
|
+
Options: ${prettifyOptions(options)}
|
|
49
|
+
|
|
50
|
+
Expected: ${resolve(info.projectRoot, info.baselinePath)}
|
|
51
|
+
Actual: ${resolve(info.projectRoot, info.resultPath)}
|
|
52
|
+
Difference: ${resolve(info.projectRoot, info.diffPath)}`);
|
|
53
|
+
};
|
|
43
54
|
}
|
|
44
55
|
/**
|
|
45
56
|
* @deprecated internalized. Use `matchImageSnapshot` directly instead.
|
|
@@ -53,11 +64,11 @@ export function parseImageSnapshotSubject(subject) {
|
|
|
53
64
|
return subject;
|
|
54
65
|
throw new Error(`'toMatchImageSnapshot()' expects the subject to be an element, locator, or image encoded in base64 string, but got: ${subject}`);
|
|
55
66
|
}
|
|
56
|
-
async function writeSnapshot(path, image) {
|
|
67
|
+
async function writeSnapshot(commands, path, image) {
|
|
57
68
|
const content = (await toDataURL(image)).split(',')[1];
|
|
58
69
|
return commands.writeImageSnapshot(path, content);
|
|
59
70
|
}
|
|
60
|
-
async function parseImageSnapshotOptions(taskId, options) {
|
|
71
|
+
async function parseImageSnapshotOptions(commands, taskId, options) {
|
|
61
72
|
const index = await commands.imageSnapshotNextIndex(taskId);
|
|
62
73
|
const { customizeSnapshotId, ...rest } = options;
|
|
63
74
|
const snapshotFileId = customizeSnapshotId(taskId, index);
|
|
@@ -2,7 +2,7 @@ export function prettifyOptions(options) {
|
|
|
2
2
|
if (!options)
|
|
3
3
|
return 'none';
|
|
4
4
|
return [
|
|
5
|
-
`failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? '
|
|
5
|
+
`failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? 'pixels'}`,
|
|
6
6
|
options.diffOptions ? `diffOptions: ${JSON.stringify(options.diffOptions)}` : '',
|
|
7
7
|
options.timeout ? `timeout: ${options.timeout} ms` : '',
|
|
8
8
|
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"augment.d.ts","sourceRoot":"","sources":["../../../src/client/page/augment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAErE,OAAO,QAAQ,yBAAyB,CAAC;IACxC,UAAU,WAAY,SAAQ,sBAAsB;KAAG;CACvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../../src/client/page/extend.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"extend.d.ts","sourceRoot":"","sources":["../../../src/client/page/extend.ts"],"names":[],"mappings":"AACA,OAAO,cAAc,CAAA"}
|
package/esm/client/selector.d.ts
CHANGED
|
@@ -3,7 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @see https://github.com/vitest-dev/vitest/blob/main/packages/browser/src/client/utils.ts
|
|
5
5
|
*/
|
|
6
|
-
import type { Locator } from '@vitest/browser/context';
|
|
7
|
-
export declare function convertToSelector(elementOrLocator: Element | Locator): string;
|
|
8
6
|
export declare function convertElementToCssSelector(element: Element): string;
|
|
9
7
|
//# sourceMappingURL=selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/client/selector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/client/selector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,UAM3D"}
|
package/esm/client/selector.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return convertElementToCssSelector(elementOrLocator);
|
|
7
|
-
}
|
|
8
|
-
if ('selector' in elementOrLocator) {
|
|
9
|
-
return elementOrLocator.selector;
|
|
10
|
-
}
|
|
11
|
-
throw new Error('Expected element or locator to be an instance of Element or Locator.');
|
|
12
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Most of the code in this file is copied from Vitest.
|
|
3
|
+
*
|
|
4
|
+
* @see https://github.com/vitest-dev/vitest/blob/main/packages/browser/src/client/utils.ts
|
|
5
|
+
*/
|
|
13
6
|
export function convertElementToCssSelector(element) {
|
|
14
7
|
if (!element || !(element instanceof Element)) {
|
|
15
8
|
throw new Error(`Expected DOM element to be an instance of Element, received ${typeof element}`);
|
package/esm/commands.d.ts
CHANGED
|
@@ -2,4 +2,6 @@ export * from './server/commands/has_image_snapshot.ts';
|
|
|
2
2
|
export * from './server/commands/image_snapshot_next_index.ts';
|
|
3
3
|
export * from './server/commands/match_image_snapshot.ts';
|
|
4
4
|
export * from './server/commands/setup_vis_suite.ts';
|
|
5
|
+
export * from './server/commands/prepare_image_snapshot_comparison.ts';
|
|
6
|
+
export * from './server/commands/write_image_snapshot.ts';
|
|
5
7
|
//# sourceMappingURL=commands.d.ts.map
|
package/esm/commands.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,cAAc,yCAAyC,CAAA;AACvD,cAAc,gDAAgD,CAAA;AAC9D,cAAc,2CAA2C,CAAA;AACzD,cAAc,sCAAsC,CAAA"}
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,cAAc,yCAAyC,CAAA;AACvD,cAAc,gDAAgD,CAAA;AAC9D,cAAc,2CAA2C,CAAA;AACzD,cAAc,sCAAsC,CAAA;AACpD,cAAc,wDAAwD,CAAA;AACtE,cAAc,2CAA2C,CAAA"}
|
package/esm/commands.js
CHANGED
|
@@ -2,3 +2,5 @@ export * from "./server/commands/has_image_snapshot.js";
|
|
|
2
2
|
export * from "./server/commands/image_snapshot_next_index.js";
|
|
3
3
|
export * from "./server/commands/match_image_snapshot.js";
|
|
4
4
|
export * from "./server/commands/setup_vis_suite.js";
|
|
5
|
+
export * from "./server/commands/prepare_image_snapshot_comparison.js";
|
|
6
|
+
export * from "./server/commands/write_image_snapshot.js";
|
package/esm/index.d.ts
CHANGED
package/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,8BAA8B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,4BAA4B,CAAA;AACnC,OAAO,0BAA0B,CAAA;AAEjC,cAAc,8BAA8B,CAAA"}
|
package/esm/index.js
CHANGED
package/esm/presets/auto.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../src/presets/auto.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../src/presets/auto.ts"],"names":[],"mappings":"AACA,OAAO,4BAA4B,CAAA;AACnC,OAAO,0BAA0B,CAAA"}
|
package/esm/presets/auto.js
CHANGED
package/esm/presets/manual.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manual.d.ts","sourceRoot":"","sources":["../../src/presets/manual.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"manual.d.ts","sourceRoot":"","sources":["../../src/presets/manual.ts"],"names":[],"mappings":"AACA,OAAO,4BAA4B,CAAA;AACnC,OAAO,0BAA0B,CAAA"}
|
package/esm/presets/manual.js
CHANGED
|
@@ -50,7 +50,6 @@ export declare function createVisContext(): {
|
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
52
|
};
|
|
53
|
-
export declare function getSuiteId(state: VisState, testPath: string, options: VisOptions): string;
|
|
54
53
|
export declare function createSuite(state: VisState, testPath: string, options: VisOptions): {
|
|
55
54
|
suiteId: string;
|
|
56
55
|
suite: {
|
|
@@ -60,4 +59,5 @@ export declare function createSuite(state: VisState, testPath: string, options:
|
|
|
60
59
|
tasks: {};
|
|
61
60
|
};
|
|
62
61
|
};
|
|
62
|
+
export declare function getSuiteId(state: VisState, testPath: string, options: VisOptions): string;
|
|
63
63
|
//# sourceMappingURL=vis_context.logic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vis_context.logic.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.logic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAKpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAEtD,MAAM,MAAM,4BAA4B,GAAG;IAC1C,OAAO,EAAE;QACR,MAAM,EAAE;YACP,IAAI,EAAE,MAAM,CAAA;YACZ,eAAe,EAAE;gBAChB,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;aACtC,CAAA;YACD,WAAW,EAAE,MAAM,CAAA;YACnB,WAAW,EAAE,MAAM,CAAA;SACnB,CAAA;KACD,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAgB,gBAAgB;yBAMV,UAAU;;;;IAY9B;;;;OAIG;wBACuB,4BAA4B;8BAY5B,MAAM,QAAQ,MAAM,YAAY;QAAE,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE;;;;;2BAiB1E,MAAM,UAAU,MAAM;+BAGlB,MAAM,UAAU,MAAM,kBAAkB,MAAM,GAAG,SAAS;8BAI3D;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,kBAAkB,MAAM,GAAG,SAAS;2BAMlF,MAAM,UAAU,MAAM;;;;;;;;;;EAe9C;AAuBD,wBAAgB,
|
|
1
|
+
{"version":3,"file":"vis_context.logic.d.ts","sourceRoot":"","sources":["../../src/server/vis_context.logic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAKpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAEtD,MAAM,MAAM,4BAA4B,GAAG;IAC1C,OAAO,EAAE;QACR,MAAM,EAAE;YACP,IAAI,EAAE,MAAM,CAAA;YACZ,eAAe,EAAE;gBAChB,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;aACtC,CAAA;YACD,WAAW,EAAE,MAAM,CAAA;YACnB,WAAW,EAAE,MAAM,CAAA;SACnB,CAAA;KACD,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAgB,gBAAgB;yBAMV,UAAU;;;;IAY9B;;;;OAIG;wBACuB,4BAA4B;8BAY5B,MAAM,QAAQ,MAAM,YAAY;QAAE,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE;;;;;2BAiB1E,MAAM,UAAU,MAAM;+BAGlB,MAAM,UAAU,MAAM,kBAAkB,MAAM,GAAG,SAAS;8BAI3D;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,kBAAkB,MAAM,GAAG,SAAS;2BAMlF,MAAM,UAAU,MAAM;;;;;;;;;;EAe9C;AAuBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU;;;;;;;;EAWjF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,UAEhF"}
|
|
@@ -99,9 +99,6 @@ async function setupState(suite, visOptions) {
|
|
|
99
99
|
await Promise.allSettled([ctx.rimraf(join(state.snapshotDiffDir)), ctx.rimraf(join(state.snapshotResultDir))]);
|
|
100
100
|
return state;
|
|
101
101
|
}
|
|
102
|
-
export function getSuiteId(state, testPath, options) {
|
|
103
|
-
return getSnapshotSubpath(relative(state.projectPath, testPath), options);
|
|
104
|
-
}
|
|
105
102
|
export function createSuite(state, testPath, options) {
|
|
106
103
|
const suiteId = getSuiteId(state, testPath, options);
|
|
107
104
|
return {
|
|
@@ -114,3 +111,6 @@ export function createSuite(state, testPath, options) {
|
|
|
114
111
|
},
|
|
115
112
|
};
|
|
116
113
|
}
|
|
114
|
+
export function getSuiteId(state, testPath, options) {
|
|
115
|
+
return getSnapshotSubpath(relative(state.projectPath, testPath), options);
|
|
116
|
+
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -111,6 +111,24 @@ vis.presets.theme({
|
|
|
111
111
|
})
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
+
### TypeScript Configuration
|
|
115
|
+
|
|
116
|
+
The main usage of this addon is to use the `toMatchImageSnapshot` matcher.
|
|
117
|
+
|
|
118
|
+
Since it is exposed under the `expect` object of `vitest`,
|
|
119
|
+
you typically do not need to import `storybook-addon-vis` directly.
|
|
120
|
+
|
|
121
|
+
Because of this, TypeScript may not recognize the matcher.
|
|
122
|
+
To address this, you can add the following to your `tsconfig.json`:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"compilerOptions": {
|
|
127
|
+
"types": ["vitest-plugin-vis"]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
114
132
|
## Usage
|
|
115
133
|
|
|
116
134
|
### Auto Snapshot
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ImageSnapshotMatcher } from './to_match_image_snapshot.types.ts'
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
namespace jest {
|
|
5
|
+
// biome-ignore lint/correctness/noUnusedVariables: augmentation must have matching type params.
|
|
6
|
+
interface Matchers<R, T> extends ImageSnapshotMatcher {}
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { expect } from 'vitest'
|
|
2
2
|
import { toMatchImageSnapshot } from './to_match_image_snapshot.ts'
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
declare global {
|
|
6
|
-
namespace jest {
|
|
7
|
-
// biome-ignore lint/correctness/noUnusedVariables: augmentation must have matching type params.
|
|
8
|
-
interface Matchers<R, T> extends ImageSnapshotMatcher {}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
3
|
+
import './augment.ts'
|
|
11
4
|
|
|
12
5
|
expect.extend({ toMatchImageSnapshot })
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { commands } from '@vitest/browser/context'
|
|
1
2
|
import type { AsyncExpectationResult } from '@vitest/expect'
|
|
2
3
|
import { ctx } from '../ctx.ts'
|
|
3
|
-
import {
|
|
4
|
+
import { imageSnapshotMatcher } from '../match_image_snapshot.ts'
|
|
4
5
|
import { success } from './expectation_result.ts'
|
|
5
6
|
import type { ToMatchImageSnapshotOptions } from './to_match_image_snapshot.types.ts'
|
|
6
7
|
|
|
@@ -24,5 +25,5 @@ export function toMatchImageSnapshot(
|
|
|
24
25
|
)
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
return
|
|
28
|
+
return imageSnapshotMatcher(commands)(test, subject, options).then(() => success)
|
|
28
29
|
}
|
|
@@ -11,4 +11,10 @@ export interface ImageSnapshotMatcher {
|
|
|
11
11
|
export interface ToMatchImageSnapshotOptions
|
|
12
12
|
extends ImageSnapshotTimeoutOptions,
|
|
13
13
|
ImageSnapshotIdOptions,
|
|
14
|
-
ImageSnapshotCompareOptions {
|
|
14
|
+
ImageSnapshotCompareOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Expect the matcher to fail.
|
|
17
|
+
* If it passes, it will throw an error with details.
|
|
18
|
+
*/
|
|
19
|
+
expectToFail?: boolean | undefined
|
|
20
|
+
}
|
|
@@ -4,7 +4,7 @@ export function prettifyOptions(options: ToMatchImageSnapshotOptions | undefined
|
|
|
4
4
|
if (!options) return 'none'
|
|
5
5
|
|
|
6
6
|
return [
|
|
7
|
-
`failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? '
|
|
7
|
+
`failureThreshold: ${options.failureThreshold ?? 0} ${options.failureThresholdType ?? 'pixels'}`,
|
|
8
8
|
options.diffOptions ? `diffOptions: ${JSON.stringify(options.diffOptions)}` : '',
|
|
9
9
|
options.timeout ? `timeout: ${options.timeout} ms` : '',
|
|
10
10
|
]
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { commands } from '@vitest/browser/context'
|
|
2
1
|
import dedent from 'dedent'
|
|
3
2
|
import { resolve } from 'pathe'
|
|
4
3
|
import type { Task } from 'vitest'
|
|
4
|
+
import type { ImageSnapshotNextIndexCommand } from '../commands.ts'
|
|
5
|
+
import type { PrepareImageSnapshotComparisonCommand } from '../server/commands/prepare_image_snapshot_comparison.ts'
|
|
6
|
+
import type { WriteImageSnapshotCommand } from '../server/commands/write_image_snapshot.ts'
|
|
5
7
|
import { isBase64String } from '../shared/base64.ts'
|
|
6
8
|
import { compareImage } from '../shared/compare_image.ts'
|
|
7
9
|
import { alignImagesToSameSize } from './align_images.ts'
|
|
@@ -12,54 +14,71 @@ import { convertElementToCssSelector } from './selector.ts'
|
|
|
12
14
|
import { toTaskId } from './task_id.ts'
|
|
13
15
|
import { server } from './vitest_browser_context_proxy.ts'
|
|
14
16
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
export function imageSnapshotMatcher(
|
|
18
|
+
commands: PrepareImageSnapshotComparisonCommand & WriteImageSnapshotCommand & ImageSnapshotNextIndexCommand,
|
|
19
|
+
) {
|
|
20
|
+
return async function matchImageSnapshot(test: Task, subject: any, options?: ToMatchImageSnapshotOptions) {
|
|
21
|
+
const taskId = toTaskId(test)
|
|
22
|
+
const info = await commands.prepareImageSnapshotComparison(
|
|
23
|
+
taskId,
|
|
24
|
+
parseImageSnapshotSubject(subject),
|
|
25
|
+
options?.customizeSnapshotId ? await parseImageSnapshotOptions(commands, taskId, options) : options,
|
|
26
|
+
)
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
if (!info) return
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
30
|
+
const baselineImage = await toImageData(info.baseline)
|
|
31
|
+
const resultImage = await toImageData(info.result)
|
|
32
|
+
const [baselineAlignedImage, resultAlignedImage] = alignImagesToSameSize(baselineImage, resultImage)
|
|
33
|
+
const { width, height } = baselineAlignedImage
|
|
34
|
+
const diffImage = new ImageData(width, height)
|
|
35
|
+
const { pass, diffAmount } = compareImage(
|
|
36
|
+
baselineAlignedImage.data,
|
|
37
|
+
resultAlignedImage.data,
|
|
38
|
+
diffImage.data,
|
|
39
|
+
width,
|
|
40
|
+
height,
|
|
41
|
+
options,
|
|
42
|
+
)
|
|
43
|
+
if (pass) {
|
|
44
|
+
if (options?.expectToFail) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
dedent`Snapshot \`${taskId}\` matched but expected to fail.
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
throw new Error(
|
|
47
|
-
dedent`Snapshot \`${taskId}\` mismatched
|
|
48
|
+
Options: ${prettifyOptions(options)}
|
|
49
|
+
DiffAmount: ${options.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`
|
|
53
|
-
: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`
|
|
54
|
-
: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`
|
|
51
|
+
Expected: ${resolve(info.projectRoot, info.baselinePath)}
|
|
52
|
+
Actual: ${resolve(info.projectRoot, info.resultPath)}`,
|
|
53
|
+
)
|
|
55
54
|
}
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
if (server.config.snapshotOptions.updateSnapshot === 'all') {
|
|
58
|
+
await writeSnapshot(commands, info.baselinePath, resultImage)
|
|
59
|
+
return
|
|
60
|
+
}
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
await writeSnapshot(commands, info.diffPath, diffImage)
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
throw new Error(
|
|
65
|
+
dedent`Snapshot \`${taskId}\` mismatched
|
|
66
|
+
|
|
67
|
+
${
|
|
68
|
+
options?.failureThreshold
|
|
69
|
+
? options?.failureThresholdType === 'percent'
|
|
70
|
+
? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`
|
|
71
|
+
: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`
|
|
72
|
+
: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Options: ${prettifyOptions(options)}
|
|
76
|
+
|
|
77
|
+
Expected: ${resolve(info.projectRoot, info.baselinePath)}
|
|
78
|
+
Actual: ${resolve(info.projectRoot, info.resultPath)}
|
|
79
|
+
Difference: ${resolve(info.projectRoot, info.diffPath)}`,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
63
82
|
}
|
|
64
83
|
|
|
65
84
|
/**
|
|
@@ -74,12 +93,16 @@ export function parseImageSnapshotSubject(subject: any) {
|
|
|
74
93
|
)
|
|
75
94
|
}
|
|
76
95
|
|
|
77
|
-
async function writeSnapshot(path: string, image: ImageData) {
|
|
96
|
+
async function writeSnapshot(commands: WriteImageSnapshotCommand, path: string, image: ImageData) {
|
|
78
97
|
const content = (await toDataURL(image)).split(',')[1]!
|
|
79
98
|
return commands.writeImageSnapshot(path, content)
|
|
80
99
|
}
|
|
81
100
|
|
|
82
|
-
async function parseImageSnapshotOptions(
|
|
101
|
+
async function parseImageSnapshotOptions(
|
|
102
|
+
commands: ImageSnapshotNextIndexCommand,
|
|
103
|
+
taskId: string,
|
|
104
|
+
options: ToMatchImageSnapshotOptions,
|
|
105
|
+
) {
|
|
83
106
|
const index = await commands.imageSnapshotNextIndex(taskId)
|
|
84
107
|
const { customizeSnapshotId, ...rest } = options
|
|
85
108
|
const snapshotFileId = customizeSnapshotId!(taskId, index)
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { page } from '@vitest/browser/context'
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
declare module '@vitest/browser/context' {
|
|
5
|
-
interface BrowserPage extends HasImageSnapshotAction {}
|
|
6
|
-
}
|
|
2
|
+
import './augment.ts'
|
|
3
|
+
import { hasImageSnapshot } from './has_image_snapshot.ts'
|
|
7
4
|
|
|
8
5
|
page.extend({ hasImageSnapshot })
|
package/src/client/selector.ts
CHANGED
|
@@ -3,20 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @see https://github.com/vitest-dev/vitest/blob/main/packages/browser/src/client/utils.ts
|
|
5
5
|
*/
|
|
6
|
-
import type { Locator } from '@vitest/browser/context'
|
|
7
6
|
|
|
8
|
-
export function convertToSelector(elementOrLocator: Element | Locator): string {
|
|
9
|
-
if (!elementOrLocator) {
|
|
10
|
-
throw new Error('Expected element or locator to be defined.')
|
|
11
|
-
}
|
|
12
|
-
if (elementOrLocator instanceof Element) {
|
|
13
|
-
return convertElementToCssSelector(elementOrLocator)
|
|
14
|
-
}
|
|
15
|
-
if ('selector' in elementOrLocator) {
|
|
16
|
-
return (elementOrLocator as any).selector
|
|
17
|
-
}
|
|
18
|
-
throw new Error('Expected element or locator to be an instance of Element or Locator.')
|
|
19
|
-
}
|
|
20
7
|
export function convertElementToCssSelector(element: Element) {
|
|
21
8
|
if (!element || !(element instanceof Element)) {
|
|
22
9
|
throw new Error(`Expected DOM element to be an instance of Element, received ${typeof element}`)
|
package/src/commands.ts
CHANGED
|
@@ -2,3 +2,5 @@ export * from './server/commands/has_image_snapshot.ts'
|
|
|
2
2
|
export * from './server/commands/image_snapshot_next_index.ts'
|
|
3
3
|
export * from './server/commands/match_image_snapshot.ts'
|
|
4
4
|
export * from './server/commands/setup_vis_suite.ts'
|
|
5
|
+
export * from './server/commands/prepare_image_snapshot_comparison.ts'
|
|
6
|
+
export * from './server/commands/write_image_snapshot.ts'
|
package/src/index.ts
CHANGED
package/src/presets/auto.ts
CHANGED
package/src/presets/manual.ts
CHANGED
|
@@ -123,10 +123,6 @@ async function setupState(suite: PartialBrowserCommandContext, visOptions: VisOp
|
|
|
123
123
|
return state
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
export function getSuiteId(state: VisState, testPath: string, options: VisOptions) {
|
|
127
|
-
return getSnapshotSubpath(relative(state.projectPath, testPath), options)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
126
|
export function createSuite(state: VisState, testPath: string, options: VisOptions) {
|
|
131
127
|
const suiteId = getSuiteId(state, testPath, options)
|
|
132
128
|
return {
|
|
@@ -139,3 +135,7 @@ export function createSuite(state: VisState, testPath: string, options: VisOptio
|
|
|
139
135
|
},
|
|
140
136
|
}
|
|
141
137
|
}
|
|
138
|
+
|
|
139
|
+
export function getSuiteId(state: VisState, testPath: string, options: VisOptions) {
|
|
140
|
+
return getSnapshotSubpath(relative(state.projectPath, testPath), options)
|
|
141
|
+
}
|