vitest-plugin-vis 2.2.0 → 2.3.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/esm/client/ctx.d.ts +2 -2
- package/esm/client/ctx.d.ts.map +1 -1
- package/esm/client/ctx.js +2 -2
- package/esm/client/expect/to_match_image_snapshot.d.ts +1 -1
- package/esm/client/expect/to_match_image_snapshot.d.ts.map +1 -1
- package/esm/client/expect/to_match_image_snapshot.types.d.ts +1 -8
- package/esm/client/expect/to_match_image_snapshot.types.d.ts.map +1 -1
- package/esm/client/image_snapshot_matcher.d.ts +3 -3
- package/esm/client/image_snapshot_matcher.d.ts.map +1 -1
- package/esm/client/image_snapshot_matcher.js +7 -3
- package/esm/client/image_snapshot_matcher.logic.d.ts +1 -1
- package/esm/client/image_snapshot_matcher.logic.d.ts.map +1 -1
- package/esm/client/page/has_image_snapshot.d.ts.map +1 -1
- package/esm/client/page/has_image_snapshot.js +3 -2
- package/esm/client/should_take_snapshot.d.ts +1 -1
- package/esm/client/should_take_snapshot.d.ts.map +1 -1
- package/esm/client/should_take_snapshot.js +2 -2
- package/esm/client/snapshot_options.d.ts +2 -7
- package/esm/client/snapshot_options.d.ts.map +1 -1
- package/esm/client/snapshot_options.js +3 -6
- package/esm/client/vitest_suite_proxy.d.ts +12 -1
- package/esm/client/vitest_suite_proxy.d.ts.map +1 -1
- package/esm/client.d.ts +1 -1
- package/esm/client.d.ts.map +1 -1
- package/esm/config/vis.d.ts +3 -3
- package/esm/index.d.ts +2 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/server/commands/extend.d.ts +3 -3
- package/esm/server/commands/has_image_snapshot.d.ts +6 -2
- package/esm/server/commands/has_image_snapshot.d.ts.map +1 -1
- package/esm/server/commands/has_image_snapshot.js +2 -2
- package/esm/server/commands/match_image_snapshot.d.ts +2 -1
- package/esm/server/commands/match_image_snapshot.d.ts.map +1 -1
- package/esm/server/commands/match_image_snapshot.js +2 -2
- package/esm/server/commands/prepare_image_snapshot_comparison.d.ts +2 -1
- package/esm/server/commands/prepare_image_snapshot_comparison.d.ts.map +1 -1
- package/esm/server/commands/prepare_image_snapshot_comparison.js +2 -2
- package/esm/server/vis_context.d.ts +3 -3
- package/esm/server/vis_context.d.ts.map +1 -1
- package/esm/server/vis_context.logic.d.ts +3 -3
- package/esm/server/vis_context.logic.d.ts.map +1 -1
- package/esm/server/vis_context.logic.js +8 -7
- package/esm/setup/create_vis.d.ts +5 -5
- package/esm/setup/create_vis.d.ts.map +1 -1
- package/esm/setup/create_vis.js +6 -5
- package/esm/setup/vis.d.ts +1 -1
- package/esm/setup/vis.d.ts.map +1 -1
- package/esm/shared/types.d.ts +12 -0
- package/esm/shared/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/readme.md +4 -3
- package/src/client/ctx.ts +2 -2
- package/src/client/expect/to_match_image_snapshot.ts +1 -1
- package/src/client/expect/to_match_image_snapshot.types.ts +1 -16
- package/src/client/image_snapshot_matcher.logic.ts +1 -1
- package/src/client/image_snapshot_matcher.ts +15 -5
- package/src/client/page/has_image_snapshot.ts +9 -2
- package/src/client/should_take_snapshot.ts +3 -2
- package/src/client/snapshot_options.ts +6 -14
- package/src/client/vitest_suite_proxy.ts +8 -1
- package/src/client.ts +1 -1
- package/src/index.ts +2 -1
- package/src/server/commands/has_image_snapshot.ts +5 -7
- package/src/server/commands/match_image_snapshot.ts +4 -3
- package/src/server/commands/prepare_image_snapshot_comparison.ts +4 -3
- package/src/server/vis_context.logic.ts +18 -8
- package/src/setup/create_vis.ts +19 -17
- package/src/shared/types.ts +18 -2
package/esm/setup/create_vis.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import dedent from 'dedent';
|
|
2
2
|
import { afterEach, beforeAll } from 'vitest';
|
|
3
|
-
import {
|
|
3
|
+
import { toTaskId } from "../client.js";
|
|
4
4
|
import { ctx } from "../client/ctx.js";
|
|
5
5
|
import { shouldTakeSnapshot } from "../client/should_take_snapshot.js";
|
|
6
|
-
import { enableAuto,
|
|
6
|
+
import { enableAuto, extractAutoSnapshotOptions } from "../client/snapshot_options.js";
|
|
7
7
|
export function createVis(commands) {
|
|
8
8
|
let subjectDataTestId;
|
|
9
9
|
const vis = {
|
|
@@ -35,9 +35,10 @@ export function createVis(commands) {
|
|
|
35
35
|
const test = ctx.getCurrentTest();
|
|
36
36
|
if ((test?.result?.errors?.length ?? 0) > 0)
|
|
37
37
|
return;
|
|
38
|
-
const meta =
|
|
38
|
+
const meta = extractAutoSnapshotOptions(test);
|
|
39
39
|
if (!shouldTakeSnapshot(meta))
|
|
40
40
|
return;
|
|
41
|
+
test.meta.vis = { ...test.meta.vis, isAutoSnapshot: true };
|
|
41
42
|
await test.context.expect(getSubject(meta?.subjectDataTestId ?? subjectDataTestId)).toMatchImageSnapshot(meta);
|
|
42
43
|
},
|
|
43
44
|
matchPerTheme(themes) {
|
|
@@ -45,7 +46,7 @@ export function createVis(commands) {
|
|
|
45
46
|
const test = ctx.getCurrentTest();
|
|
46
47
|
if ((test?.result?.errors?.length ?? 0) > 0)
|
|
47
48
|
return;
|
|
48
|
-
const meta =
|
|
49
|
+
const meta = extractAutoSnapshotOptions(test);
|
|
49
50
|
if (!shouldTakeSnapshot(meta))
|
|
50
51
|
return;
|
|
51
52
|
const errors = [];
|
|
@@ -60,7 +61,7 @@ export function createVis(commands) {
|
|
|
60
61
|
.toMatchImageSnapshot({
|
|
61
62
|
...meta,
|
|
62
63
|
customizeSnapshotId: meta?.customizeSnapshotId
|
|
63
|
-
? ({ id, index }) => `${meta.customizeSnapshotId({ id, index })}-${themeId}`
|
|
64
|
+
? ({ id, index }) => `${meta.customizeSnapshotId({ id, index, isAutoSnapshot: true })}-${themeId}`
|
|
64
65
|
: ({ id }) => `${id}-${themeId}`,
|
|
65
66
|
});
|
|
66
67
|
}
|
package/esm/setup/vis.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Visual test configuration on the client side.
|
|
3
3
|
*/
|
|
4
|
-
export declare const vis: import("./create_vis.ts").VisClientConfigurator<import("../index.ts").SnapshotMeta<
|
|
4
|
+
export declare const vis: import("./create_vis.ts").VisClientConfigurator<import("../index.ts").SnapshotMeta<import("../index.ts").ComparisonMethod>>;
|
|
5
5
|
//# sourceMappingURL=vis.d.ts.map
|
package/esm/setup/vis.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vis.d.ts","sourceRoot":"","sources":["../../src/setup/vis.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"vis.d.ts","sourceRoot":"","sources":["../../src/setup/vis.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,GAAG,6HAAsB,CAAA"}
|
package/esm/shared/types.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface ImageSnapshotIdOptions {
|
|
|
18
18
|
customizeSnapshotId?: (context: {
|
|
19
19
|
id: string;
|
|
20
20
|
index: number;
|
|
21
|
+
isAutoSnapshot: boolean;
|
|
21
22
|
}) => string;
|
|
22
23
|
}
|
|
23
24
|
export type ComparisonMethod = 'pixel' | 'ssim';
|
|
@@ -59,4 +60,15 @@ export type AutoSnapshotOptions = {
|
|
|
59
60
|
*/
|
|
60
61
|
subjectDataTestId?: string | undefined;
|
|
61
62
|
};
|
|
63
|
+
export type ToMatchImageSnapshotOptions<M extends ComparisonMethod = 'pixel'> = ImageSnapshotTimeoutOptions & ImageSnapshotIdOptions & ImageSnapshotCompareOptions<M> & {
|
|
64
|
+
/**
|
|
65
|
+
* Expect the matcher to fail.
|
|
66
|
+
* If it passes, it will throw an error with details.
|
|
67
|
+
*/
|
|
68
|
+
expectToFail?: boolean | undefined;
|
|
69
|
+
};
|
|
70
|
+
export type SnapshotMeta<M extends ComparisonMethod> = ToMatchImageSnapshotOptions<M> & AutoSnapshotOptions & {
|
|
71
|
+
enable?: boolean | undefined;
|
|
72
|
+
[key: string]: unknown;
|
|
73
|
+
};
|
|
62
74
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,YAAY,CAAA;AACxC,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,SAAS,CAAA;AAIrD,MAAM,WAAW,2BAA2B;IAC3C;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC/B,EAAE,EAAE,MAAM,CAAA;QACV,KAAK,EAAE,MAAM,CAAA;QACb,cAAc,EAAE,OAAO,CAAA;KACvB,KAAK,MAAM,CAAA;CACZ;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAA;AAE/C,MAAM,MAAM,uBAAuB,GAAG;IACrC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;IACtD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,GAAG,MAAM,IAAI;IAC/C,gBAAgB,EAAE,CAAC,CAAA;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,SAAS,CAAA;CAC9C,CAAA;AACD,MAAM,MAAM,sBAAsB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,gBAAgB,CAAC,EAAE,CAAC,GAAG,SAAS,CAAA;IAChC;;OAEG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;CAC1D,CAAA;AAED,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO,IAAI,CAAC,CAAC,SAAS,MAAM,GAC9F,qBAAqB,CAAC,CAAC,CAAC,GACxB,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAC5B,uBAAuB,CAAA;AAExB,MAAM,MAAM,mBAAmB,GAAG;IACjC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA;AACD,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO,IAAI,2BAA2B,GAC1G,sBAAsB,GACtB,2BAA2B,CAAC,CAAC,CAAC,GAAG;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAClC,CAAA;AAEF,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,gBAAgB,IAAI,2BAA2B,CAAC,CAAC,CAAC,GACpF,mBAAmB,GAAG;IACrB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB,CAAA"}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -83,7 +83,8 @@ export default defineConfig({
|
|
|
83
83
|
}) => `__vis__/${ci ? platform : 'local'}`,
|
|
84
84
|
platform: '...', // {process.platform} or `local` (deprecated use `snapshotRootDir` instead)
|
|
85
85
|
customizeSnapshotSubpath: (subpath) => trimCommonFolder(subpath),
|
|
86
|
-
|
|
86
|
+
// will change to "isAutoSnapshot ? `${id}-auto` : `${id}-${index}`" in the next major release.
|
|
87
|
+
customizeSnapshotId: ({ id, index, isAutoSnapshot }) => `${id}-${index}`,
|
|
87
88
|
// set a default subject (e.g. 'subject') to capture image snapshot
|
|
88
89
|
subjectDataTestId: undefined,
|
|
89
90
|
comparisonMethod: 'pixel',
|
|
@@ -217,7 +218,7 @@ setAutoSnapshotOptions(true /* or false */)
|
|
|
217
218
|
setAutoSnapshotOptions({
|
|
218
219
|
enable: true,
|
|
219
220
|
comparisonMethod: 'pixel',
|
|
220
|
-
customizeSnapshotId: ({ id, index }) => `${id}-custom-${index}`,
|
|
221
|
+
customizeSnapshotId: ({ id, index, isAutoSnapshot }) => `${id}-custom-${index}`,
|
|
221
222
|
// pixelmatch or ssim.js options, depending on `comparisonMethod`.
|
|
222
223
|
diffOptions: { threshold: 0.01 },
|
|
223
224
|
failureThreshold: 0.01,
|
|
@@ -285,7 +286,7 @@ it('manual snapshot with options', async ({ expect }) => {
|
|
|
285
286
|
page.render(<div data-testid="subject">hello world</div>)
|
|
286
287
|
const subject = page.getByTestId('subject')
|
|
287
288
|
await expect(subject).toMatchImageSnapshot({
|
|
288
|
-
customizeSnapshotId: ({ id, index }) => `${id}-custom-${index}`,
|
|
289
|
+
customizeSnapshotId: ({ id, index, isAutoSnapshot }) => `${id}-custom-${index}`,
|
|
289
290
|
failureThreshold: 0.01,
|
|
290
291
|
failureThresholdType: 'percent',
|
|
291
292
|
diffOptions: {
|
package/src/client/ctx.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { getCurrentSuite, getCurrentTest } from './vitest_suite_proxy.ts'
|
|
2
2
|
|
|
3
3
|
export const ctx = {
|
|
4
|
-
autoEnabled:
|
|
4
|
+
autoEnabled: undefined as boolean | undefined,
|
|
5
5
|
getCurrentTest,
|
|
6
6
|
getCurrentSuite,
|
|
7
7
|
__test__reset() {
|
|
8
8
|
ctx.getCurrentTest = getCurrentTest
|
|
9
9
|
ctx.getCurrentSuite = getCurrentSuite
|
|
10
|
-
ctx.autoEnabled =
|
|
10
|
+
ctx.autoEnabled = undefined
|
|
11
11
|
},
|
|
12
12
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { commands } from '@vitest/browser/context'
|
|
2
2
|
import type { AsyncExpectationResult } from '@vitest/expect'
|
|
3
|
+
import type { ToMatchImageSnapshotOptions } from '../../shared/types.ts'
|
|
3
4
|
import { ctx } from '../ctx.ts'
|
|
4
5
|
import { imageSnapshotMatcher } from '../image_snapshot_matcher.ts'
|
|
5
6
|
import { success } from './expectation_result.ts'
|
|
6
|
-
import type { ToMatchImageSnapshotOptions } from './to_match_image_snapshot.types.ts'
|
|
7
7
|
|
|
8
8
|
export function toMatchImageSnapshot(
|
|
9
9
|
/**
|
|
@@ -1,20 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ComparisonMethod,
|
|
3
|
-
ImageSnapshotCompareOptions,
|
|
4
|
-
ImageSnapshotIdOptions,
|
|
5
|
-
ImageSnapshotTimeoutOptions,
|
|
6
|
-
} from '../../shared/types.ts'
|
|
1
|
+
import type { ComparisonMethod, ToMatchImageSnapshotOptions } from '../../shared/types.ts'
|
|
7
2
|
|
|
8
3
|
export interface ImageSnapshotMatcher {
|
|
9
4
|
toMatchImageSnapshot<M extends ComparisonMethod>(options?: ToMatchImageSnapshotOptions<M> | undefined): Promise<void>
|
|
10
5
|
}
|
|
11
|
-
|
|
12
|
-
export type ToMatchImageSnapshotOptions<M extends ComparisonMethod = 'pixel'> = ImageSnapshotTimeoutOptions &
|
|
13
|
-
ImageSnapshotIdOptions &
|
|
14
|
-
ImageSnapshotCompareOptions<M> & {
|
|
15
|
-
/**
|
|
16
|
-
* Expect the matcher to fail.
|
|
17
|
-
* If it passes, it will throw an error with details.
|
|
18
|
-
*/
|
|
19
|
-
expectToFail?: boolean | undefined
|
|
20
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ToMatchImageSnapshotOptions } from '
|
|
1
|
+
import type { ToMatchImageSnapshotOptions } from '../shared/types.ts'
|
|
2
2
|
|
|
3
3
|
export function prettifyOptions(options: ToMatchImageSnapshotOptions<any> | undefined) {
|
|
4
4
|
if (!options) return 'none'
|
|
@@ -1,28 +1,37 @@
|
|
|
1
|
+
import { isA } from '@vitest/expect'
|
|
1
2
|
import dedent from 'dedent'
|
|
2
3
|
import { resolve } from 'pathe'
|
|
3
|
-
import type { Task } from 'vitest'
|
|
4
4
|
import type { ImageSnapshotNextIndexCommand } from '../commands.ts'
|
|
5
5
|
import type { PrepareImageSnapshotComparisonCommand } from '../server/commands/prepare_image_snapshot_comparison.ts'
|
|
6
6
|
import type { WriteImageSnapshotCommand } from '../server/commands/write_image_snapshot.ts'
|
|
7
7
|
import { isBase64String } from '../shared/base64.ts'
|
|
8
8
|
import { compareImage } from '../shared/compare_image.ts'
|
|
9
|
+
import type { ToMatchImageSnapshotOptions } from '../shared/types.ts'
|
|
9
10
|
import { alignImagesToSameSize } from './align_images.ts'
|
|
10
|
-
import type { ToMatchImageSnapshotOptions } from './expect/to_match_image_snapshot.types.ts'
|
|
11
11
|
import { toDataURL, toImageData } from './image_data.ts'
|
|
12
12
|
import { prettifyOptions } from './image_snapshot_matcher.logic.ts'
|
|
13
13
|
import { convertElementToCssSelector } from './selector.ts'
|
|
14
14
|
import { toTaskId } from './task_id.ts'
|
|
15
15
|
import { server } from './vitest_browser_context_proxy.ts'
|
|
16
|
+
import type { CurrentTest } from './vitest_suite_proxy.ts'
|
|
16
17
|
|
|
17
18
|
export function imageSnapshotMatcher(
|
|
18
19
|
commands: PrepareImageSnapshotComparisonCommand & WriteImageSnapshotCommand & ImageSnapshotNextIndexCommand,
|
|
19
20
|
) {
|
|
20
|
-
return async function matchImageSnapshot(
|
|
21
|
+
return async function matchImageSnapshot(
|
|
22
|
+
test: CurrentTest & {},
|
|
23
|
+
subject: any,
|
|
24
|
+
options?: ToMatchImageSnapshotOptions<any>,
|
|
25
|
+
) {
|
|
26
|
+
const isAutoSnapshot = !!test.meta.vis?.isAutoSnapshot
|
|
21
27
|
const taskId = toTaskId(test)
|
|
22
28
|
const info = await commands.prepareImageSnapshotComparison(
|
|
23
29
|
taskId,
|
|
24
30
|
parseImageSnapshotSubject(subject),
|
|
25
|
-
|
|
31
|
+
isAutoSnapshot,
|
|
32
|
+
options?.customizeSnapshotId
|
|
33
|
+
? await parseImageSnapshotOptions(commands, taskId, isAutoSnapshot, options)
|
|
34
|
+
: options,
|
|
26
35
|
)
|
|
27
36
|
|
|
28
37
|
if (!info) return
|
|
@@ -103,10 +112,11 @@ async function writeSnapshot(commands: WriteImageSnapshotCommand, path: string,
|
|
|
103
112
|
async function parseImageSnapshotOptions(
|
|
104
113
|
commands: ImageSnapshotNextIndexCommand,
|
|
105
114
|
taskId: string,
|
|
115
|
+
isAutoSnapshot: boolean,
|
|
106
116
|
options: ToMatchImageSnapshotOptions<any>,
|
|
107
117
|
) {
|
|
108
118
|
const index = await commands.imageSnapshotNextIndex(taskId)
|
|
109
119
|
const { customizeSnapshotId, ...rest } = options
|
|
110
|
-
const snapshotFileId = customizeSnapshotId!({ id: taskId, index })
|
|
120
|
+
const snapshotFileId = customizeSnapshotId!({ id: taskId, index, isAutoSnapshot })
|
|
111
121
|
return { ...rest, snapshotFileId }
|
|
112
122
|
}
|
|
@@ -23,11 +23,18 @@ export function hasImageSnapshot(this: BrowserPage, options?: ImageSnapshotIdOpt
|
|
|
23
23
|
)
|
|
24
24
|
}
|
|
25
25
|
const taskId = toTaskId(test)
|
|
26
|
+
const isAutoSnapshot = !!test.meta.vis?.isAutoSnapshot
|
|
26
27
|
if (options?.customizeSnapshotId) {
|
|
27
28
|
return commands
|
|
28
29
|
.imageSnapshotNextIndex(taskId)
|
|
29
|
-
.then((index) =>
|
|
30
|
+
.then((index) =>
|
|
31
|
+
commands.hasImageSnapshot(
|
|
32
|
+
taskId,
|
|
33
|
+
options.customizeSnapshotId!({ id: taskId, index, isAutoSnapshot }),
|
|
34
|
+
isAutoSnapshot,
|
|
35
|
+
),
|
|
36
|
+
)
|
|
30
37
|
}
|
|
31
38
|
|
|
32
|
-
return commands.hasImageSnapshot(taskId)
|
|
39
|
+
return commands.hasImageSnapshot(taskId, undefined, isAutoSnapshot)
|
|
33
40
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { SnapshotMeta } from '../shared/types.ts'
|
|
1
2
|
import { ctx } from './ctx.ts'
|
|
2
|
-
import {
|
|
3
|
+
import { extractAutoSnapshotOptions } from './snapshot_options.ts'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Determine should snapshot be taken.
|
|
@@ -9,6 +10,6 @@ import { type SnapshotMeta, getAutoSnapshotOptions } from './snapshot_options.ts
|
|
|
9
10
|
* disabled by `!snapshot` tag: false
|
|
10
11
|
*/
|
|
11
12
|
export function shouldTakeSnapshot(meta?: SnapshotMeta<any> | undefined) {
|
|
12
|
-
const m = meta ??
|
|
13
|
+
const m = meta ?? extractAutoSnapshotOptions(ctx.getCurrentTest())
|
|
13
14
|
return document.body.childElementCount > 0 && m?.enable
|
|
14
15
|
}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { NAME } from '../shared/constants.ts'
|
|
2
|
-
import type {
|
|
2
|
+
import type { ComparisonMethod, SnapshotMeta } from '../shared/types.ts'
|
|
3
3
|
import { ctx } from './ctx.ts'
|
|
4
|
-
import type { ToMatchImageSnapshotOptions } from './expect/to_match_image_snapshot.types.ts'
|
|
5
|
-
|
|
6
|
-
export type SnapshotMeta<M extends ComparisonMethod> = ToMatchImageSnapshotOptions<M> &
|
|
7
|
-
AutoSnapshotOptions & {
|
|
8
|
-
enable?: boolean | undefined
|
|
9
|
-
[key: string]: unknown
|
|
10
|
-
}
|
|
11
4
|
|
|
12
5
|
type Suite = { meta: Record<string, any>; suite?: Suite | undefined }
|
|
13
6
|
|
|
@@ -66,7 +59,9 @@ function parseMeta<M extends ComparisonMethod>(meta: boolean | SnapshotMeta<M>):
|
|
|
66
59
|
return typeof meta === 'boolean' ? ({ enable: meta } as any) : { enable: true, ...meta }
|
|
67
60
|
}
|
|
68
61
|
|
|
69
|
-
export function
|
|
62
|
+
export function extractAutoSnapshotOptions<M extends SnapshotMeta<any> = SnapshotMeta<any>>(
|
|
63
|
+
task: MetaTask,
|
|
64
|
+
): M | undefined {
|
|
70
65
|
if (!task) return
|
|
71
66
|
|
|
72
67
|
const list: any[] = []
|
|
@@ -79,11 +74,8 @@ export function getAutoSnapshotOptions<M extends SnapshotMeta<any> = SnapshotMet
|
|
|
79
74
|
list.push(task.meta)
|
|
80
75
|
return list.reduce(
|
|
81
76
|
(acc, cur) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return Object.assign({}, acc, meta)
|
|
85
|
-
}
|
|
86
|
-
return acc
|
|
77
|
+
const meta = cur?.[NAME]
|
|
78
|
+
return meta ? Object.assign({}, acc, meta) : acc
|
|
87
79
|
},
|
|
88
80
|
{ enable: ctx.autoEnabled },
|
|
89
81
|
)
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { NAME } from '../shared/constants.ts'
|
|
2
|
+
import type { SnapshotMeta } from '../shared/types.ts'
|
|
3
|
+
|
|
1
4
|
let vitestSuite: Awaited<typeof import('vitest/suite')>
|
|
2
5
|
|
|
3
6
|
if ((globalThis as any).__vitest_browser__) {
|
|
@@ -6,5 +9,9 @@ if ((globalThis as any).__vitest_browser__) {
|
|
|
6
9
|
})
|
|
7
10
|
}
|
|
8
11
|
|
|
9
|
-
export
|
|
12
|
+
export type CurrentTest = ReturnType<typeof vitestSuite.getCurrentTest> & {
|
|
13
|
+
meta: { [NAME]?: SnapshotMeta<'pixel' | 'ssim'> & { isAutoSnapshot?: boolean | undefined } }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const getCurrentTest = () => vitestSuite?.getCurrentTest() as CurrentTest
|
|
10
17
|
export const getCurrentSuite = () => vitestSuite?.getCurrentSuite()
|
package/src/client.ts
CHANGED
|
@@ -2,6 +2,6 @@ export * from './client/expect/expectation_result.ts'
|
|
|
2
2
|
export type * from './client/expect/to_match_image_snapshot.types.ts'
|
|
3
3
|
export * from './client/image_snapshot_matcher.ts'
|
|
4
4
|
export * from './client/should_take_snapshot.ts'
|
|
5
|
-
export {
|
|
5
|
+
export { setAutoSnapshotOptions, type MetaTask } from './client/snapshot_options.ts'
|
|
6
6
|
export * from './client/task_id.ts'
|
|
7
7
|
export type * from './shared/types.ts'
|
package/src/index.ts
CHANGED
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
import './client/expect/augment.ts'
|
|
3
3
|
import './client/page/augment.ts'
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export { setAutoSnapshotOptions, type MetaTask } from './client/snapshot_options.ts'
|
|
6
|
+
export type * from './shared/types.ts'
|
|
@@ -3,15 +3,13 @@ import { visContext } from '../vis_context.ts'
|
|
|
3
3
|
import { assertTestPathDefined } from './_assertions.ts'
|
|
4
4
|
|
|
5
5
|
export interface HasImageSnapshotCommand {
|
|
6
|
-
hasImageSnapshot(taskId: string, snapshotId
|
|
6
|
+
hasImageSnapshot(taskId: string, snapshotId: string | undefined, isAutoSnapshot: boolean): Promise<boolean>
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export const hasImageSnapshot: BrowserCommand<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
snapshotId,
|
|
13
|
-
) => {
|
|
9
|
+
export const hasImageSnapshot: BrowserCommand<
|
|
10
|
+
[taskId: string, snapshotId: string | undefined, isAutoSnapshot: boolean]
|
|
11
|
+
> = async (context, taskId, snapshotId, isAutoSnapshot) => {
|
|
14
12
|
assertTestPathDefined(context, 'hasImageSnapshot')
|
|
15
13
|
|
|
16
|
-
return visContext.hasImageSnapshot(context.testPath, taskId, snapshotId)
|
|
14
|
+
return visContext.hasImageSnapshot(context.testPath, taskId, snapshotId, isAutoSnapshot)
|
|
17
15
|
}
|
|
@@ -20,6 +20,7 @@ export interface MatchImageSnapshotCommand {
|
|
|
20
20
|
matchImageSnapshot: (
|
|
21
21
|
taskId: string | undefined,
|
|
22
22
|
subject: string,
|
|
23
|
+
isAutoSnapshot: boolean,
|
|
23
24
|
options?: MatchImageSnapshotOptions | undefined,
|
|
24
25
|
) => Promise<void>
|
|
25
26
|
}
|
|
@@ -34,15 +35,15 @@ export type MatchImageSnapshotOptions = ImageSnapshotTimeoutOptions &
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export const matchImageSnapshot: BrowserCommand<
|
|
37
|
-
[taskId: string, subject: string, options?: MatchImageSnapshotOptions | undefined]
|
|
38
|
-
> = async (context, taskId, subject, options) => {
|
|
38
|
+
[taskId: string, subject: string, isAutoSnapshot: boolean, options?: MatchImageSnapshotOptions | undefined]
|
|
39
|
+
> = async (context, taskId, subject, isAutoSnapshot, options) => {
|
|
39
40
|
assertTestPathDefined(context, 'matchImageSnapshot')
|
|
40
41
|
|
|
41
42
|
// vitest:browser passes in `null` when not defined
|
|
42
43
|
if (!options) options = {}
|
|
43
44
|
options.timeout = options.timeout ?? 30000
|
|
44
45
|
|
|
45
|
-
const info = visContext.getSnapshotInfo(context.testPath, taskId, options)
|
|
46
|
+
const info = visContext.getSnapshotInfo(context.testPath, taskId, isAutoSnapshot, options)
|
|
46
47
|
const baselineBuffer = await file.tryReadFile(info.baselinePath)
|
|
47
48
|
if (!baselineBuffer) {
|
|
48
49
|
if (isBase64String(subject)) {
|
|
@@ -27,20 +27,21 @@ export interface PrepareImageSnapshotComparisonCommand {
|
|
|
27
27
|
prepareImageSnapshotComparison: (
|
|
28
28
|
taskId: string | undefined,
|
|
29
29
|
subject: string,
|
|
30
|
+
isAutoSnapshot: boolean,
|
|
30
31
|
options?: MatchImageSnapshotOptions | undefined,
|
|
31
32
|
) => Promise<ImageSnapshotComparisonInfo | undefined>
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export const prepareImageSnapshotComparison: BrowserCommand<
|
|
35
|
-
[taskId: string, snapshotId: string, options?: MatchImageSnapshotOptions | undefined]
|
|
36
|
-
> = async (context, taskId, subject, options) => {
|
|
36
|
+
[taskId: string, snapshotId: string, isAutoSnapshot: boolean, options?: MatchImageSnapshotOptions | undefined]
|
|
37
|
+
> = async (context, taskId, subject, isAutoSnapshot, options) => {
|
|
37
38
|
assertTestPathDefined(context, 'prepareImageSnapshotComparison')
|
|
38
39
|
|
|
39
40
|
// vitest:browser passes in `null` when not defined
|
|
40
41
|
if (!options) options = {}
|
|
41
42
|
options.timeout = options.timeout ?? 30000
|
|
42
43
|
|
|
43
|
-
const info = visContext.getSnapshotInfo(context.testPath, taskId, options)
|
|
44
|
+
const info = visContext.getSnapshotInfo(context.testPath, taskId, isAutoSnapshot, options)
|
|
44
45
|
const baselineBuffer = await file.tryReadFile(info.baselinePath)
|
|
45
46
|
if (!baselineBuffer) {
|
|
46
47
|
if (isBase64String(subject)) {
|
|
@@ -43,11 +43,16 @@ export function createVisContext() {
|
|
|
43
43
|
await Promise.allSettled([ctx.rimraf(suite.diffDir), ctx.rimraf(suite.resultDir)])
|
|
44
44
|
return pick(state, 'subjectDataTestId')
|
|
45
45
|
},
|
|
46
|
-
getSnapshotInfo(
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
getSnapshotInfo(
|
|
47
|
+
testPath: string,
|
|
48
|
+
name: string,
|
|
49
|
+
isAutoSnapshot: boolean,
|
|
50
|
+
options?: { snapshotFileId?: string | undefined },
|
|
51
|
+
) {
|
|
52
|
+
const suiteInfo = context.getSuiteInfo(testPath, name)
|
|
53
|
+
const snapshotFilename = context.getSnapshotFilename(suiteInfo, options?.snapshotFileId, isAutoSnapshot)
|
|
49
54
|
|
|
50
|
-
const { baselineDir, resultDir, diffDir, task } =
|
|
55
|
+
const { baselineDir, resultDir, diffDir, task } = suiteInfo
|
|
51
56
|
|
|
52
57
|
task.count = task.count + 1
|
|
53
58
|
const baselinePath = join(baselineDir, snapshotFilename)
|
|
@@ -64,17 +69,22 @@ export function createVisContext() {
|
|
|
64
69
|
getTaskCount(testPath: string, taskId: string) {
|
|
65
70
|
return context.getSuiteInfo(testPath, taskId).task.count
|
|
66
71
|
},
|
|
67
|
-
hasImageSnapshot(testPath: string, taskId: string, snapshotFileId: string | undefined) {
|
|
72
|
+
hasImageSnapshot(testPath: string, taskId: string, snapshotFileId: string | undefined, isAutoSnapshot: boolean) {
|
|
68
73
|
const info = context.getSuiteInfo(testPath, taskId)
|
|
69
|
-
return file.existFile(join(info.baselineDir, context.getSnapshotFilename(info, snapshotFileId)))
|
|
74
|
+
return file.existFile(join(info.baselineDir, context.getSnapshotFilename(info, snapshotFileId, isAutoSnapshot)))
|
|
70
75
|
},
|
|
71
|
-
getSnapshotFilename(
|
|
72
|
-
|
|
76
|
+
getSnapshotFilename(
|
|
77
|
+
info: { taskId: string; task: { count: number } },
|
|
73
78
|
|
|
79
|
+
snapshotFileId: string | undefined,
|
|
80
|
+
isAutoSnapshot: boolean,
|
|
81
|
+
) {
|
|
82
|
+
if (snapshotFileId) return `${snapshotFileId}.png`
|
|
74
83
|
const customizeSnapshotId = visOptions.customizeSnapshotId ?? (({ id, index }) => `${id}-${index}`)
|
|
75
84
|
return `${customizeSnapshotId({
|
|
76
85
|
id: info.taskId,
|
|
77
86
|
index: info.task.count,
|
|
87
|
+
isAutoSnapshot,
|
|
78
88
|
})}.png`
|
|
79
89
|
},
|
|
80
90
|
getSuiteInfo(testPath: string, taskId: string) {
|
package/src/setup/create_vis.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import dedent from 'dedent'
|
|
2
2
|
import { afterEach, beforeAll } from 'vitest'
|
|
3
|
-
import { type
|
|
3
|
+
import { type ComparisonMethod, type SnapshotMeta, toTaskId } from '../client.ts'
|
|
4
4
|
import { ctx } from '../client/ctx.ts'
|
|
5
5
|
import { shouldTakeSnapshot } from '../client/should_take_snapshot.ts'
|
|
6
|
-
import { enableAuto,
|
|
6
|
+
import { enableAuto, extractAutoSnapshotOptions } from '../client/snapshot_options.ts'
|
|
7
7
|
import type { SetupVisSuiteCommand } from '../server/commands/setup_vis_suite.ts'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Visual test configuration on the client side.
|
|
11
11
|
*/
|
|
12
|
-
export type VisClientConfigurator<
|
|
12
|
+
export type VisClientConfigurator<SM extends SnapshotMeta<ComparisonMethod>> = {
|
|
13
13
|
presets: {
|
|
14
14
|
/**
|
|
15
15
|
* Enable visual testing.
|
|
@@ -45,23 +45,23 @@ export type VisClientConfigurator<M extends SnapshotMeta<any>> = {
|
|
|
45
45
|
* })
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
|
-
theme(themes: Record<string, (options: M) => Promise<boolean> | Promise<void> | boolean | void>): void
|
|
48
|
+
theme<M>(themes: Record<string, (options: M & SM) => Promise<boolean> | Promise<void> | boolean | void>): void
|
|
49
49
|
}
|
|
50
50
|
beforeAll: {
|
|
51
51
|
setup(): Promise<void>
|
|
52
52
|
}
|
|
53
53
|
afterEach: {
|
|
54
54
|
matchImageSnapshot(): Promise<void>
|
|
55
|
-
matchPerTheme(
|
|
56
|
-
themes: Record<string, (options: M) => Promise<boolean> | Promise<void> | boolean | void>,
|
|
55
|
+
matchPerTheme<M>(
|
|
56
|
+
themes: Record<string, (options: M & SM) => Promise<boolean> | Promise<void> | boolean | void>,
|
|
57
57
|
): () => Promise<void>
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export function createVis<
|
|
61
|
+
export function createVis<SM extends SnapshotMeta<ComparisonMethod>>(commands: SetupVisSuiteCommand) {
|
|
62
62
|
let subjectDataTestId: string | undefined
|
|
63
63
|
|
|
64
|
-
const vis: VisClientConfigurator<
|
|
64
|
+
const vis: VisClientConfigurator<SM> = {
|
|
65
65
|
presets: {
|
|
66
66
|
enable() {
|
|
67
67
|
beforeAll(vis.beforeAll.setup)
|
|
@@ -75,7 +75,7 @@ export function createVis<M extends SnapshotMeta<any>>(commands: SetupVisSuiteCo
|
|
|
75
75
|
afterEach(vis.afterEach.matchImageSnapshot)
|
|
76
76
|
enableAuto()
|
|
77
77
|
},
|
|
78
|
-
theme(themes
|
|
78
|
+
theme(themes) {
|
|
79
79
|
beforeAll(vis.beforeAll.setup)
|
|
80
80
|
afterEach(vis.afterEach.matchPerTheme(themes))
|
|
81
81
|
},
|
|
@@ -91,38 +91,40 @@ export function createVis<M extends SnapshotMeta<any>>(commands: SetupVisSuiteCo
|
|
|
91
91
|
|
|
92
92
|
if ((test?.result?.errors?.length ?? 0) > 0) return
|
|
93
93
|
|
|
94
|
-
const meta =
|
|
94
|
+
const meta = extractAutoSnapshotOptions(test)
|
|
95
95
|
if (!shouldTakeSnapshot(meta)) return
|
|
96
96
|
|
|
97
|
+
test.meta.vis = { ...test.meta.vis, isAutoSnapshot: true }
|
|
98
|
+
|
|
97
99
|
await test!.context.expect(getSubject(meta?.subjectDataTestId ?? subjectDataTestId)).toMatchImageSnapshot(meta)
|
|
98
100
|
},
|
|
99
|
-
matchPerTheme(themes
|
|
101
|
+
matchPerTheme(themes) {
|
|
100
102
|
return async function matchImageSnapshot() {
|
|
101
103
|
const test = ctx.getCurrentTest()
|
|
102
104
|
if ((test?.result?.errors?.length ?? 0) > 0) return
|
|
103
105
|
|
|
104
|
-
const meta =
|
|
106
|
+
const meta = extractAutoSnapshotOptions(test)
|
|
105
107
|
if (!shouldTakeSnapshot(meta)) return
|
|
106
|
-
const errors:
|
|
108
|
+
const errors: Array<[string, Error]> = []
|
|
107
109
|
for (const themeId in themes) {
|
|
108
110
|
try {
|
|
109
111
|
await new Promise((a) => setTimeout(a, 10))
|
|
110
|
-
const r = await themes[themeId]!(meta!)
|
|
112
|
+
const r = await themes[themeId]!(meta! as any)
|
|
111
113
|
if (r === false) continue
|
|
112
114
|
await test!.context
|
|
113
115
|
.expect(getSubject(meta?.subjectDataTestId ?? subjectDataTestId))
|
|
114
116
|
.toMatchImageSnapshot({
|
|
115
117
|
...meta,
|
|
116
118
|
customizeSnapshotId: meta?.customizeSnapshotId
|
|
117
|
-
? ({ id, index }) => `${meta.customizeSnapshotId!({ id, index })}-${themeId}`
|
|
119
|
+
? ({ id, index }) => `${meta.customizeSnapshotId!({ id, index, isAutoSnapshot: true })}-${themeId}`
|
|
118
120
|
: ({ id }) => `${id}-${themeId}`,
|
|
119
121
|
})
|
|
120
122
|
} catch (error) {
|
|
121
|
-
errors.push([themeId, error])
|
|
123
|
+
errors.push([themeId, error as Error])
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
126
|
if (errors.length > 0) {
|
|
125
|
-
if (errors.length === 1) throw errors[0][1]
|
|
127
|
+
if (errors.length === 1) throw errors[0]![1]
|
|
126
128
|
const taskId = toTaskId(test!)
|
|
127
129
|
throw new AggregateError(
|
|
128
130
|
errors,
|
package/src/shared/types.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type pixelMatch from 'pixelmatch'
|
|
2
2
|
import type { Options as SsimOptions } from 'ssim.js'
|
|
3
|
+
import type { getCurrentTest } from 'vitest/suite'
|
|
4
|
+
import type { NAME } from './constants.ts'
|
|
3
5
|
|
|
4
6
|
export interface ImageSnapshotTimeoutOptions {
|
|
5
7
|
/**
|
|
@@ -19,9 +21,8 @@ export interface ImageSnapshotIdOptions {
|
|
|
19
21
|
*/
|
|
20
22
|
customizeSnapshotId?: (context: {
|
|
21
23
|
id: string
|
|
22
|
-
// width: number
|
|
23
|
-
// height: number
|
|
24
24
|
index: number
|
|
25
|
+
isAutoSnapshot: boolean
|
|
25
26
|
}) => string
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -71,3 +72,18 @@ export type AutoSnapshotOptions = {
|
|
|
71
72
|
*/
|
|
72
73
|
subjectDataTestId?: string | undefined
|
|
73
74
|
}
|
|
75
|
+
export type ToMatchImageSnapshotOptions<M extends ComparisonMethod = 'pixel'> = ImageSnapshotTimeoutOptions &
|
|
76
|
+
ImageSnapshotIdOptions &
|
|
77
|
+
ImageSnapshotCompareOptions<M> & {
|
|
78
|
+
/**
|
|
79
|
+
* Expect the matcher to fail.
|
|
80
|
+
* If it passes, it will throw an error with details.
|
|
81
|
+
*/
|
|
82
|
+
expectToFail?: boolean | undefined
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type SnapshotMeta<M extends ComparisonMethod> = ToMatchImageSnapshotOptions<M> &
|
|
86
|
+
AutoSnapshotOptions & {
|
|
87
|
+
enable?: boolean | undefined
|
|
88
|
+
[key: string]: unknown
|
|
89
|
+
}
|