storybook-addon-vis 0.9.0 → 0.10.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/dist/chunk-6D7Y6NEG.js +16 -0
- package/dist/chunk-6D7Y6NEG.js.map +1 -0
- package/dist/{chunk-EYGWSOX2.js → chunk-B2M7JPBQ.js} +87 -29
- package/dist/chunk-B2M7JPBQ.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/preview-CL-IBwxx.d.ts +10 -0
- package/dist/preview.d.ts +1 -1
- package/dist/preview.js +2 -2
- package/dist/{types-CqNsMDsD.d.ts → types-DtnVxcLK.d.ts} +22 -4
- package/dist/vitest-setup.d.ts +3 -3
- package/dist/vitest-setup.js +5 -23
- package/dist/vitest-setup.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +16 -8
- package/src/@vitest/browser/page.image_snapshot.ts +1 -3
- package/src/@vitest/browser/types.ts +5 -0
- package/src/expect.to_match_image_snapshot.ts +12 -5
- package/src/should_take_snapshot.ts +1 -2
- package/src/state.ts +86 -45
- package/src/storybook/preview.ts +5 -5
- package/src/types.ts +13 -2
- package/src/vis.spec.ts +37 -4
- package/src/vis.ts +4 -22
- package/dist/chunk-EYGWSOX2.js.map +0 -1
- package/dist/chunk-FLRCYKBG.js +0 -17
- package/dist/chunk-FLRCYKBG.js.map +0 -1
- package/dist/preview-C2OcE4hp.d.ts +0 -6
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { toMatchImageSnapshot, state } from './chunk-B2M7JPBQ.js';
|
|
2
|
+
import { expect } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
expect.extend({ toMatchImageSnapshot });
|
|
5
|
+
var storybookPreviewVis = defineVisPreview();
|
|
6
|
+
function defineVisPreview() {
|
|
7
|
+
return {
|
|
8
|
+
beforeEach(ctx) {
|
|
9
|
+
return state.setupStory(ctx);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { defineVisPreview, storybookPreviewVis };
|
|
15
|
+
//# sourceMappingURL=chunk-6D7Y6NEG.js.map
|
|
16
|
+
//# sourceMappingURL=chunk-6D7Y6NEG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storybook/preview.ts"],"names":[],"mappings":";;;AAKA,MAAO,CAAA,MAAA,CAAO,EAAE,oBAAA,EAAsB,CAAA;AAE/B,IAAM,sBAAsB,gBAAiB;AAE7C,SAAS,gBAAuC,GAAA;AACtD,EAAO,OAAA;AAAA,IACN,WAAW,GAAmB,EAAA;AAC7B,MAAO,OAAA,KAAA,CAAM,WAAW,GAAG,CAAA;AAAA;AAC5B,GACD;AACD","file":"chunk-6D7Y6NEG.js","sourcesContent":["import { expect } from '@storybook/test'\nimport type { ProjectAnnotations, Renderer, StoryContext } from 'storybook/internal/types'\nimport { toMatchImageSnapshot } from '../expect.to_match_image_snapshot'\nimport { state } from '../state'\n\nexpect.extend({ toMatchImageSnapshot })\n\nexport const storybookPreviewVis = defineVisPreview()\n\nexport function defineVisPreview<R extends Renderer>() {\n\treturn {\n\t\tbeforeEach(ctx: StoryContext) {\n\t\t\treturn state.setupStory(ctx)\n\t\t},\n\t} satisfies ProjectAnnotations<R>\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getByAltText, getByRole, getByTestId, getByText, getByTitle, getByPlaceholderText, getByLabelText } from '@storybook/test';
|
|
2
|
-
import { join } from 'pathe';
|
|
2
|
+
import { basename, join, dirname, relative } from 'pathe';
|
|
3
|
+
import { required, omit } from 'type-plus';
|
|
3
4
|
import { getCurrentTest } from 'vitest/suite';
|
|
4
5
|
import dedent from 'dedent';
|
|
5
6
|
import pixelmatch from 'pixelmatch';
|
|
6
|
-
import { required } from 'type-plus';
|
|
7
7
|
|
|
8
8
|
// src/@vitest/browser/context.ts
|
|
9
9
|
|
|
@@ -25,27 +25,82 @@ function toSnapshotId(taskName) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// src/state.ts
|
|
28
|
-
|
|
29
|
-
name
|
|
30
|
-
testFilepath
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
28
|
+
function createStore() {
|
|
29
|
+
let name;
|
|
30
|
+
let testFilepath;
|
|
31
|
+
let testFilename;
|
|
32
|
+
let baselineDir;
|
|
33
|
+
let resultDir;
|
|
34
|
+
let diffDir;
|
|
35
|
+
let snapshot;
|
|
36
|
+
let suiteOptions = {};
|
|
37
|
+
let tags;
|
|
38
|
+
let parameters;
|
|
39
|
+
let taskName;
|
|
40
|
+
let id;
|
|
41
|
+
const state2 = {
|
|
42
|
+
baselineDir,
|
|
43
|
+
resultDir,
|
|
44
|
+
diffDir,
|
|
45
|
+
snapshot: {},
|
|
46
|
+
async setupSuite(suite, options) {
|
|
47
|
+
name = suite.name;
|
|
48
|
+
testFilepath = suite.file.filepath;
|
|
49
|
+
testFilename = basename(testFilepath);
|
|
50
|
+
const projectDir = testFilepath.slice(0, -name.length);
|
|
51
|
+
const snapshotPath = join(
|
|
52
|
+
projectDir,
|
|
53
|
+
options?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`
|
|
54
|
+
);
|
|
55
|
+
const currentDir = dirname(testFilepath);
|
|
56
|
+
baselineDir = relative(currentDir, join(snapshotPath, testFilename));
|
|
57
|
+
resultDir = relative(currentDir, join(snapshotPath, "__results__", testFilename));
|
|
58
|
+
diffDir = relative(currentDir, join(snapshotPath, "__diff_output__", testFilename));
|
|
59
|
+
suiteOptions = options ?? {};
|
|
60
|
+
snapshot = snapshot ?? {};
|
|
61
|
+
if (!snapshot[testFilepath]) {
|
|
62
|
+
snapshot[testFilepath] = {};
|
|
63
|
+
await commands.rmDir(resultDir);
|
|
64
|
+
await commands.rmDir(diffDir);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
setupStory(ctx2) {
|
|
68
|
+
tags = ctx2.tags;
|
|
69
|
+
parameters = ctx2.parameters;
|
|
70
|
+
},
|
|
71
|
+
shouldTakeSnapshot() {
|
|
72
|
+
if (!tags) return false;
|
|
73
|
+
return tags.lastIndexOf("!snapshot") < tags.lastIndexOf("snapshot");
|
|
74
|
+
},
|
|
75
|
+
getName() {
|
|
76
|
+
return taskName;
|
|
77
|
+
},
|
|
78
|
+
getTimeout(timeout) {
|
|
79
|
+
return timeout ?? suiteOptions.timeout ?? 3e4;
|
|
80
|
+
},
|
|
81
|
+
mergeMatchImageSnapshotOptions(options) {
|
|
82
|
+
return required(omit(suiteOptions, "snapshotPath"), parameters?.snapshot, options);
|
|
83
|
+
},
|
|
84
|
+
getSnapshotFilePaths(options) {
|
|
85
|
+
const test = getCurrentTest();
|
|
86
|
+
taskName = test.name;
|
|
87
|
+
id = toSnapshotId(taskName);
|
|
88
|
+
snapshot[testFilepath][id] = snapshot[testFilepath][id] ?? { index: 1 };
|
|
89
|
+
const index = snapshot[testFilepath][id].index;
|
|
90
|
+
const customizeSnapshotId = suiteOptions.customizeSnapshotId ?? options?.customizeSnapshotId ?? ((id2, index2) => `${id2}-${index2}`);
|
|
91
|
+
const snapshotFilename = `${customizeSnapshotId(id, index)}.png`;
|
|
92
|
+
const baselinePath = join(baselineDir, snapshotFilename);
|
|
93
|
+
const resultPath = join(resultDir, snapshotFilename);
|
|
94
|
+
const diffPath = join(diffDir, snapshotFilename);
|
|
95
|
+
return { snapshotFilename, baselinePath, resultPath, diffPath };
|
|
96
|
+
},
|
|
97
|
+
incrementSnapshotIndex() {
|
|
98
|
+
snapshot[testFilepath][id].index++;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
return state2;
|
|
102
|
+
}
|
|
103
|
+
var state = createStore();
|
|
49
104
|
|
|
50
105
|
// src/@vitest/browser/page.has_image_snapshot.ts
|
|
51
106
|
async function hasImageSnapshot(options) {
|
|
@@ -95,7 +150,7 @@ async function imageSnapshot(options) {
|
|
|
95
150
|
base64: true,
|
|
96
151
|
path: resultPath,
|
|
97
152
|
element: options?.element,
|
|
98
|
-
timeout: options?.timeout
|
|
153
|
+
timeout: state.getTimeout(options?.timeout)
|
|
99
154
|
});
|
|
100
155
|
state.incrementSnapshotIndex();
|
|
101
156
|
const image = await toImageData(screenshot.base64);
|
|
@@ -222,8 +277,11 @@ async function toMatchImageSnapshotInternal(actual, options) {
|
|
|
222
277
|
}
|
|
223
278
|
const originalImage = await toImageData(baseline);
|
|
224
279
|
const [resultImage, baselineImage] = alignImagesToSameSize(subject.image, originalImage);
|
|
225
|
-
|
|
226
|
-
|
|
280
|
+
const { pass, diffAmount, diffImage } = compareImage(
|
|
281
|
+
baselineImage,
|
|
282
|
+
resultImage,
|
|
283
|
+
state.mergeMatchImageSnapshotOptions(options)
|
|
284
|
+
);
|
|
227
285
|
if (!pass) {
|
|
228
286
|
if (server.config.snapshotOptions.updateSnapshot === "all") {
|
|
229
287
|
await writeSnapshot(`${subject.baselinePath}`, resultImage);
|
|
@@ -232,7 +290,7 @@ async function toMatchImageSnapshotInternal(actual, options) {
|
|
|
232
290
|
await writeSnapshot(`${subject.diffPath}`, diffImage);
|
|
233
291
|
return {
|
|
234
292
|
pass: false,
|
|
235
|
-
message: () => dedent`Snapshot \`${state.
|
|
293
|
+
message: () => dedent`Snapshot \`${state.getName()}\` mismatched
|
|
236
294
|
|
|
237
295
|
${options?.failureThreshold ? options?.failureThresholdType === "percent" ? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.` : `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.` : `Expected image to match but was differ by ${options?.failureThresholdType === "percent" ? `${diffAmount}%` : `${diffAmount} pixels`}.`}
|
|
238
296
|
|
|
@@ -293,5 +351,5 @@ function toThresholdUnit({ failureThresholdType, width, height }, pixelDiff) {
|
|
|
293
351
|
}
|
|
294
352
|
|
|
295
353
|
export { cdp, commands, page, server, state, toMatchImageSnapshot };
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
297
|
-
//# sourceMappingURL=chunk-
|
|
354
|
+
//# sourceMappingURL=chunk-B2M7JPBQ.js.map
|
|
355
|
+
//# sourceMappingURL=chunk-B2M7JPBQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/@vitest/browser/constants.ts","../src/@vitest/browser/image_snapshot.logic.ts","../src/state.ts","../src/@vitest/browser/page.has_image_snapshot.ts","../src/image_data.ts","../src/@vitest/browser/page.image_snapshot.ts","../src/@vitest/browser/context.ts","../src/image_resizer.ts","../src/expect.to_match_image_snapshot.ts"],"names":["state","ctx","id","index","getCurrentTest"],"mappings":"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","file":"chunk-B2M7JPBQ.js","sourcesContent":["export const imageSnapshotSymbol = Symbol.for('storybook-addon-vis/imageSnapshot')\n\nexport const imageSnapshotStubSymbol = Symbol.for('storybook-addon-vis/imageSnapshotStub')\n","import { imageSnapshotSymbol } from './constants.js'\nimport type { ImageSnapshot } from './types.js'\n\nexport function isImageSnapshot(subject: any): subject is ImageSnapshot {\n\treturn !!subject && subject.type === imageSnapshotSymbol\n}\n\nexport function assertImageSnapshot(subject: any): asserts subject is ImageSnapshot {\n\tif (!isImageSnapshot(subject)) {\n\t\tthrow new Error('Expected subject to be an image snapshot')\n\t}\n}\n\nexport function toSnapshotId(taskName: string) {\n\treturn `${taskName.replace(/[^a-z0-9]/gi, '-').toLowerCase()}`\n}\n","import { basename, dirname, join, relative } from 'pathe'\nimport type { StoryContext } from 'storybook/internal/types'\nimport { omit, required } from 'type-plus'\nimport { getCurrentTest } from 'vitest/suite'\nimport { commands } from './@vitest/browser/context.js'\nimport { toSnapshotId } from './@vitest/browser/image_snapshot.logic'\nimport type { ImageSnapshotOptions } from './@vitest/browser/types'\nimport type { MatchImageSnapshotOptions } from './expect.to_match_image_snapshot'\nimport type { VisOptions } from './types.js'\n\nfunction createStore() {\n\t// test suite (runner.beforeAll) states\n\tlet name: string\n\tlet testFilepath: string\n\tlet testFilename: string\n\tlet baselineDir: string\n\tlet resultDir: string\n\tlet diffDir: string\n\tlet snapshot: Record<string, Record<string, { index: number }>>\n\tlet suiteOptions: VisOptions = {}\n\n\t// story states (story.beforeEach)\n\tlet tags: string[] | undefined\n\tlet parameters: Record<string, any> | undefined\n\tlet taskName: string\n\tlet id: string\n\n\tconst state = {\n\t\tbaselineDir,\n\t\tresultDir,\n\t\tdiffDir,\n\t\tsnapshot: {},\n\t\tasync setupSuite(suite: { file: { filepath: string }; name: string }, options?: VisOptions) {\n\t\t\tname = suite.name\n\t\t\ttestFilepath = suite.file.filepath\n\t\t\ttestFilename = basename(testFilepath)\n\t\t\tconst projectDir = testFilepath.slice(0, -name.length)\n\t\t\tconst snapshotPath = join(\n\t\t\t\tprojectDir,\n\t\t\t\toptions?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`,\n\t\t\t)\n\t\t\tconst currentDir = dirname(testFilepath)\n\t\t\tbaselineDir = relative(currentDir, join(snapshotPath, testFilename))\n\t\t\tresultDir = relative(currentDir, join(snapshotPath, '__results__', testFilename))\n\t\t\tdiffDir = relative(currentDir, join(snapshotPath, '__diff_output__', testFilename))\n\n\t\t\tsuiteOptions = options ?? {}\n\t\t\tsnapshot = snapshot ?? {}\n\t\t\tif (!snapshot[testFilepath]) {\n\t\t\t\tsnapshot[testFilepath] = {}\n\t\t\t\tawait commands.rmDir(resultDir)\n\t\t\t\tawait commands.rmDir(diffDir)\n\t\t\t}\n\t\t},\n\t\tsetupStory(ctx: StoryContext) {\n\t\t\ttags = ctx.tags\n\t\t\tparameters = ctx.parameters\n\t\t},\n\t\tshouldTakeSnapshot() {\n\t\t\tif (!tags) return false\n\t\t\treturn tags.lastIndexOf('!snapshot') < tags.lastIndexOf('snapshot')\n\t\t},\n\t\tgetName() {\n\t\t\treturn taskName\n\t\t},\n\t\tgetTimeout(timeout?: number | undefined) {\n\t\t\treturn timeout ?? suiteOptions.timeout ?? 30000\n\t\t},\n\t\tmergeMatchImageSnapshotOptions(options?: MatchImageSnapshotOptions) {\n\t\t\treturn required(omit(suiteOptions, 'snapshotPath'), parameters?.snapshot, options)\n\t\t},\n\t\tgetSnapshotFilePaths(options?: ImageSnapshotOptions | undefined) {\n\t\t\tconst test = getCurrentTest()\n\t\t\ttaskName = test.name\n\t\t\tid = toSnapshotId(taskName)\n\t\t\tsnapshot[testFilepath][id] = snapshot[testFilepath][id] ?? { index: 1 }\n\n\t\t\tconst index = snapshot[testFilepath][id]!.index\n\t\t\tconst customizeSnapshotId =\n\t\t\t\tsuiteOptions.customizeSnapshotId ?? options?.customizeSnapshotId ?? ((id, index) => `${id}-${index}`)\n\t\t\tconst snapshotFilename = `${customizeSnapshotId(id, index)}.png`\n\t\t\tconst baselinePath = join(baselineDir, snapshotFilename)\n\t\t\tconst resultPath = join(resultDir, snapshotFilename)\n\t\t\tconst diffPath = join(diffDir, snapshotFilename)\n\t\t\treturn { snapshotFilename, baselinePath, resultPath, diffPath }\n\t\t},\n\t\tincrementSnapshotIndex() {\n\t\t\tsnapshot[testFilepath][id]!.index++\n\t\t},\n\t}\n\treturn state\n}\n\nexport const state = createStore()\n","import type { BrowserPage } from '@vitest/browser/context'\nimport { join } from 'pathe'\nimport { state } from '../../state'\nimport { commands } from './context'\nimport type { CustomizeSnapshotIdOptions } from './types'\n\nexport interface HasImageSnapshotAction {\n\thasImageSnapshot(this: BrowserPage, options?: CustomizeSnapshotIdOptions | undefined): Promise<boolean>\n}\n\n/**\n * Check if the snapshot image exists.\n */\nexport async function hasImageSnapshot(this: BrowserPage, options?: CustomizeSnapshotIdOptions | undefined) {\n\tconst { baselinePath } = state.getSnapshotFilePaths(options)\n\treturn commands.existFile(baselinePath)\n}\n","export function toImageData(base64: string) {\n\treturn new Promise<ImageData>((resolve, reject) => {\n\t\tconst img = new Image()\n\t\timg.src = `data:image/png;base64,${base64}`\n\n\t\timg.onload = () => {\n\t\t\tconst canvas = document.createElement('canvas')\n\t\t\tcanvas.width = img.width\n\t\t\tcanvas.height = img.height\n\t\t\tconst ctx = canvas.getContext('2d')!\n\t\t\tctx.drawImage(img, 0, 0)\n\t\t\tresolve(ctx.getImageData(0, 0, canvas.width, canvas.height))\n\t\t}\n\n\t\timg.onerror = () => {\n\t\t\treject(new Error('Failed to load image'))\n\t\t}\n\t})\n}\n\nexport async function toDataURL(imageData: ImageData) {\n\tconst canvas = document.createElement('canvas')\n\tcanvas.width = imageData.width\n\tcanvas.height = imageData.height\n\tconst ctx = canvas.getContext('2d')!\n\tctx.putImageData(imageData, 0, 0)\n\treturn new Promise<string>((resolve) => {\n\t\tcanvas.toBlob((blob) => {\n\t\t\tconst reader = new FileReader()\n\t\t\treader.onload = () => {\n\t\t\t\tresolve(reader.result as string)\n\t\t\t}\n\t\t\treader.readAsDataURL(blob!)\n\t\t})\n\t})\n}\n","import type { BrowserPage } from '@vitest/browser/context'\nimport { toImageData } from '../../image_data.js'\nimport { state } from '../../state.js'\nimport { imageSnapshotSymbol } from './constants.js'\nimport type { ImageSnapshot, ImageSnapshotOptions } from './types.js'\n\nexport interface ImageSnapshotAction {\n\timageSnapshot(this: BrowserPage, options?: ImageSnapshotOptions | undefined): Promise<ImageSnapshot>\n}\n\nexport async function imageSnapshot(\n\tthis: BrowserPage,\n\toptions?: ImageSnapshotOptions | undefined,\n): Promise<ImageSnapshot> {\n\tconst { snapshotFilename, baselinePath, resultPath, diffPath } = state.getSnapshotFilePaths(options)\n\tconst screenshot = await this.screenshot({\n\t\tbase64: true,\n\t\tpath: resultPath,\n\t\telement: options?.element,\n\t\ttimeout: state.getTimeout(options?.timeout),\n\t})\n\tstate.incrementSnapshotIndex()\n\tconst image = await toImageData(screenshot.base64)\n\n\treturn {\n\t\ttype: imageSnapshotSymbol,\n\t\tsnapshotFilename,\n\t\tbaselinePath,\n\t\tresultPath,\n\t\tdiffPath,\n\t\tbase64: screenshot.base64,\n\t\timage,\n\t}\n}\n","import {\n\tgetByAltText,\n\tgetByLabelText,\n\tgetByPlaceholderText,\n\tgetByRole,\n\tgetByTestId,\n\tgetByText,\n\tgetByTitle,\n} from '@storybook/test'\nimport type { BrowserCommands, BrowserPage, CDPSession, Platform } from '@vitest/browser/context'\nimport type { SerializedConfig } from 'vitest'\nimport { imageSnapshotStubSymbol } from './constants'\nimport { hasImageSnapshot } from './page.has_image_snapshot'\nimport { imageSnapshot } from './page.image_snapshot'\n\nlet ctx: Awaited<typeof import('@vitest/browser/context')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('@vitest/browser/context').then((m) => {\n\t\tctx = m\n\t\tpage.extend({ imageSnapshot, hasImageSnapshot })\n\t})\n}\n\n// TODO: stub the functions within the `CDPSession`\n// when we better understands the use cases\nexport function cdp(): CDPSession {\n\treturn ctx?.cdp() ?? ({} as any)\n}\n\nexport const commands = new Proxy<BrowserCommands>({} as any, {\n\tget(target, prop) {\n\t\treturn (target as any)[prop] ?? (ctx?.commands as any)[prop]\n\t},\n})\n\nexport const page = new Proxy<BrowserPage>(\n\t{\n\t\tgetByAltText,\n\t\tgetByRole,\n\t\tgetByTestId,\n\t\tgetByText,\n\t\tgetByTitle,\n\t\tgetByPlaceholder: getByPlaceholderText,\n\t\tgetByLabelText,\n\t} as any,\n\t{\n\t\tget(target, prop) {\n\t\t\treturn ((target as any)[prop] ?? ctx?.page)\n\t\t\t\t? (ctx?.page as any)[prop]\n\t\t\t\t: () => {\n\t\t\t\t\t\tif (prop === 'imageSnapshot') {\n\t\t\t\t\t\t\treturn { type: imageSnapshotStubSymbol }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (prop === 'hasImageSnapshot') {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.info(`\\`page.${prop.toString()}\\` does not exist when running in browser`)\n\t\t\t\t\t}\n\t\t},\n\t},\n)\n\nexport const server = new Proxy<{\n\t/**\n\t * Platform the Vitest server is running on.\n\t * The same as calling `process.platform` on the server.\n\t */\n\tplatform: Platform\n\t/**\n\t * Runtime version of the Vitest server.\n\t * The same as calling `process.version` on the server.\n\t */\n\tversion: string\n\t/**\n\t * Name of the browser provider.\n\t */\n\tprovider: string\n\t/**\n\t * Name of the current browser.\n\t */\n\tbrowser: string\n\t/**\n\t * Available commands for the browser.\n\t * @see {@link https://vitest.dev/guide/browser/commands}\n\t */\n\tcommands: BrowserCommands\n\t/**\n\t * Serialized test config.\n\t */\n\tconfig: SerializedConfig\n}>({} as any, {\n\tget(target, prop) {\n\t\treturn (target as any)[prop] ?? (ctx?.server as any)[prop]\n\t},\n})\n","export const createImageResizer =\n\t({ width, height }: { width: number; height: number }) =>\n\t(image: ImageData) => {\n\t\tif (image.width === width && image.height === height) {\n\t\t\treturn image\n\t\t}\n\t\tconst inArea = (x: number, y: number) => y <= image.height && x <= image.width\n\t\tconst result = new ImageData(width, height, { colorSpace: image.colorSpace })\n\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst idx = (width * y + x) << 2\n\t\t\t\tif (inArea(x, y)) {\n\t\t\t\t\tconst old = (image.width * y + x) << 2\n\t\t\t\t\tresult.data[idx] = image.data[old]\n\t\t\t\t\tresult.data[idx + 1] = image.data[old + 1]\n\t\t\t\t\tresult.data[idx + 2] = image.data[old + 2]\n\t\t\t\t\tresult.data[idx + 3] = image.data[old + 3]\n\t\t\t\t} else {\n\t\t\t\t\tresult.data[idx] = 0\n\t\t\t\t\tresult.data[idx + 1] = 0\n\t\t\t\t\tresult.data[idx + 2] = 0\n\t\t\t\t\tresult.data[idx + 3] = 64\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n\n// slower\nexport const createImageResizer2 =\n\t({ width, height }: { width: number; height: number }) =>\n\t(image: ImageData) => {\n\t\tif (image.width === width && image.height === height) {\n\t\t\treturn image\n\t\t}\n\t\tconst inArea = (x: number, y: number) => y <= image.height && x <= image.width\n\t\tconst result = new ImageData(width, height, { colorSpace: image.colorSpace })\n\n\t\tconst copyBytes = image.width * 4\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tresult.data.set(image.data.slice(y * image.width, copyBytes), y * width * 4)\n\t\t\tfor (let x = image.width; x < width; x++) {\n\t\t\t\tconst idx = (width * y + x) << 2\n\t\t\t\tif (!inArea(x, y)) {\n\t\t\t\t\tresult.data[idx] = 0\n\t\t\t\t\tresult.data[idx + 1] = 0\n\t\t\t\t\tresult.data[idx + 2] = 0\n\t\t\t\t\tresult.data[idx + 3] = 64\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n","import type { AsyncExpectationResult } from '@vitest/expect'\nimport dedent from 'dedent'\nimport pixelmatch, { type PixelmatchOptions } from 'pixelmatch'\nimport { getCurrentTest } from 'vitest/suite'\nimport { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'\nimport { commands, page, server } from './@vitest/browser/context.js'\nimport { assertImageSnapshot, isImageSnapshot } from './@vitest/browser/image_snapshot.logic.js'\nimport { toDataURL, toImageData } from './image_data.js'\nimport { createImageResizer } from './image_resizer.js'\nimport { state } from './state.js'\n\nexport interface ImageSnapshotMatcher {\n\ttoMatchImageSnapshot(options?: MatchImageSnapshotOptions): Promise<void>\n}\n\nexport type MatchImageSnapshotOptions = {\n\t/**\n\t * Custom options passed to 'pixelmatch'\n\t */\n\tdiffOptions?: PixelmatchOptions | undefined\n\t/**\n\t * Failure threshold should measure in `pixel` or `percent`.\n\t *\n\t * Default is `pixel`.\n\t */\n\tfailureThresholdType?: 'pixel' | 'percent' | undefined\n\t/**\n\t * Failure tolerance threshold.\n\t *\n\t * Default is `0`.\n\t */\n\tfailureThreshold?: number | undefined\n}\n\nexport async function toMatchImageSnapshot(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tconst promise = toMatchImageSnapshotInternal(actual, options)\n\tconst test = getCurrentTest()\n\tif (!test) return promise\n\ttest.promises ??= []\n\ttest.promises.push(promise)\n\treturn promise\n}\n\nasync function toMatchImageSnapshotInternal(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tlet subject = await actual\n\tif (subject?.type === imageSnapshotStubSymbol) {\n\t\treturn success\n\t}\n\tif (!isImageSnapshot(subject)) {\n\t\tif (subject?.path && subject?.base64) {\n\t\t\treturn {\n\t\t\t\tpass: false,\n\t\t\t\tactual: subject,\n\t\t\t\tmessage: () =>\n\t\t\t\t\t'`toMatchImageSnapshot()` expects the subject to be the result of `page.imageSnapshot()`, but seems like you are using `page.screenshot()`?',\n\t\t\t}\n\t\t}\n\n\t\tif (typeof subject !== 'object') {\n\t\t\treturn {\n\t\t\t\tpass: false,\n\t\t\t\tactual: subject,\n\t\t\t\tmessage: () =>\n\t\t\t\t\t`\\`toMatchImageSnapshot()\\` expects the subject to be an element, locator, or result of \\`page.imageSnapshot()\\`, but got: \\`${subject}\\``,\n\t\t\t}\n\t\t}\n\t\tsubject = await page.imageSnapshot({ element: subject })\n\t}\n\n\tassertImageSnapshot(subject)\n\n\tconst baseline = await tryReadSnapshot(subject.baselinePath)\n\tif (!baseline) {\n\t\tawait commands.copyFile(subject.resultPath, subject.baselinePath)\n\t\treturn success\n\t}\n\n\tconst originalImage = await toImageData(baseline)\n\tconst [resultImage, baselineImage] = alignImagesToSameSize(subject.image, originalImage)\n\n\t// const test = getCurrentTest()\n\t// console.log('test', test)\n\tconst { pass, diffAmount, diffImage } = compareImage(\n\t\tbaselineImage,\n\t\tresultImage,\n\t\tstate.mergeMatchImageSnapshotOptions(options),\n\t)\n\n\tif (!pass) {\n\t\tif (server.config.snapshotOptions.updateSnapshot === 'all') {\n\t\t\tawait writeSnapshot(`${subject.baselinePath}`, resultImage)\n\t\t\treturn success\n\t\t}\n\t\tawait writeSnapshot(`${subject.diffPath}`, diffImage)\n\t\treturn {\n\t\t\tpass: false,\n\t\t\tmessage: () =>\n\t\t\t\tdedent`Snapshot \\`${state.getName()}\\` mismatched\n\n\t\t\t${\n\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\t\t\t\t\t? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`\n\t\t\t\t\t\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\t\t}\n\n\t\t\tExpected: '${subject.baselinePath}'\n\t\t\tActual: '${subject.resultPath}'\n\t\t\tDifference: '${subject.diffPath}'`,\n\t\t}\n\t}\n\treturn success\n}\n\nconst success = {\n\tpass: true,\n\tmessage: () => '',\n}\n\nfunction tryReadSnapshot(path: string): Promise<string | undefined> {\n\treturn commands.readFile(path, { encoding: 'base64' }).catch(() => undefined)\n}\nasync function writeSnapshot(path: string, image: ImageData) {\n\tconst content = (await toDataURL(image)).split(',')[1]!\n\treturn commands.writeFile(path, content, 'base64url')\n}\n\nfunction alignImagesToSameSize(image1: ImageData, image2: ImageData): [image1: ImageData, image2: ImageData] {\n\tif (isSameSize(image1, image2)) {\n\t\treturn [image1, image2]\n\t}\n\tconst size = getMaxSize(image1, image2)\n\tconst resize = createImageResizer(size)\n\treturn [resize(image1), resize(image2)]\n}\n\nfunction getMaxSize(image1: ImageData, image2: ImageData) {\n\tconst width = Math.max(image1.width, image2.width)\n\tconst height = Math.max(image1.height, image2.height)\n\treturn { width, height }\n}\n\nfunction isSameSize(image1: ImageData, image2: ImageData) {\n\treturn image1.width === image2.width && image1.height === image2.height\n}\n\nfunction compareImage(\n\tbaselineImage: ImageData,\n\tresultImage: ImageData,\n\t{ failureThreshold = 0, failureThresholdType = 'pixel', diffOptions }: MatchImageSnapshotOptions = {},\n) {\n\tconst { width, height } = resultImage\n\tconst diffImage = new ImageData(width, height)\n\n\tconst pixelDiff = pixelmatch(resultImage.data, baselineImage.data, diffImage.data, width, height, diffOptions)\n\tconst diffAmount = toThresholdUnit({ failureThresholdType, width, height }, pixelDiff)\n\n\treturn {\n\t\tpass: diffAmount <= failureThreshold,\n\t\tdiffAmount,\n\t\tdiffImage,\n\t}\n}\n\nfunction toThresholdUnit(\n\t{ failureThresholdType, width, height }: { failureThresholdType: 'pixel' | 'percent'; width: number; height: number },\n\tpixelDiff: number,\n): number {\n\tswitch (failureThresholdType) {\n\t\tcase 'pixel':\n\t\t\treturn pixelDiff\n\t\tcase 'percent':\n\t\t\treturn (pixelDiff / (width * height)) * 100\n\t\tdefault:\n\t\t\tthrow new Error(`Invalid failureThresholdType: ${failureThresholdType}`)\n\t}\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { M as MatchImageSnapshotOptions } from './types-
|
|
2
|
-
export { C as CustomizeSnapshotIdOptions, d as ImageSnapshot, I as ImageSnapshotMatcher, b as ImageSnapshotOptions, V as VisOptions, c as cdp, a as commands, p as page, s as server, t as toMatchImageSnapshot } from './types-
|
|
3
|
-
export { d as defineVisPreview, s as storybookPreviewVis } from './preview-
|
|
1
|
+
import { M as MatchImageSnapshotOptions } from './types-DtnVxcLK.js';
|
|
2
|
+
export { C as CustomizeSnapshotIdOptions, d as ImageSnapshot, I as ImageSnapshotMatcher, b as ImageSnapshotOptions, V as VisOptions, c as cdp, a as commands, p as page, s as server, t as toMatchImageSnapshot } from './types-DtnVxcLK.js';
|
|
3
|
+
export { d as defineVisPreview, s as storybookPreviewVis } from './preview-CL-IBwxx.js';
|
|
4
4
|
import '@vitest/browser/context';
|
|
5
|
+
import 'vitest';
|
|
5
6
|
import '@vitest/expect';
|
|
6
7
|
import 'pixelmatch';
|
|
7
|
-
import 'vitest';
|
|
8
8
|
import 'storybook/internal/types';
|
|
9
9
|
|
|
10
10
|
declare function defineSnapshotParam(snapshot: MatchImageSnapshotOptions): {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { defineVisPreview, storybookPreviewVis } from './chunk-
|
|
2
|
-
export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-
|
|
1
|
+
export { defineVisPreview, storybookPreviewVis } from './chunk-6D7Y6NEG.js';
|
|
2
|
+
export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-B2M7JPBQ.js';
|
|
3
3
|
|
|
4
4
|
// src/param.ts
|
|
5
5
|
function defineSnapshotParam(snapshot) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StoryContext, Renderer } from 'storybook/internal/types';
|
|
2
|
+
|
|
3
|
+
declare const storybookPreviewVis: {
|
|
4
|
+
beforeEach(ctx: StoryContext): void;
|
|
5
|
+
};
|
|
6
|
+
declare function defineVisPreview<R extends Renderer>(): {
|
|
7
|
+
beforeEach(ctx: StoryContext): void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export { defineVisPreview as d, storybookPreviewVis as s };
|
package/dist/preview.d.ts
CHANGED
package/dist/preview.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { BrowserPage, CDPSession, BrowserCommands, Platform } from '@vitest/browser/context';
|
|
2
|
+
import { SerializedConfig } from 'vitest';
|
|
2
3
|
import { AsyncExpectationResult } from '@vitest/expect';
|
|
3
4
|
import { PixelmatchOptions } from 'pixelmatch';
|
|
4
|
-
import { SerializedConfig } from 'vitest';
|
|
5
5
|
|
|
6
6
|
interface ImageSnapshotOptions extends CustomizeSnapshotIdOptions {
|
|
7
7
|
element?: Element;
|
|
8
|
+
/**
|
|
9
|
+
* Timeout for taking the snapshot.
|
|
10
|
+
*
|
|
11
|
+
* Default: 30000
|
|
12
|
+
*/
|
|
8
13
|
timeout?: number | undefined;
|
|
9
14
|
}
|
|
10
15
|
type CustomizeSnapshotIdOptions = {
|
|
@@ -50,6 +55,11 @@ type MatchImageSnapshotOptions = {
|
|
|
50
55
|
* Default is `pixel`.
|
|
51
56
|
*/
|
|
52
57
|
failureThresholdType?: 'pixel' | 'percent' | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Failure tolerance threshold.
|
|
60
|
+
*
|
|
61
|
+
* Default is `0`.
|
|
62
|
+
*/
|
|
53
63
|
failureThreshold?: number | undefined;
|
|
54
64
|
};
|
|
55
65
|
declare function toMatchImageSnapshot(actual: any, options?: MatchImageSnapshotOptions | undefined): AsyncExpectationResult;
|
|
@@ -134,11 +144,19 @@ declare const server: {
|
|
|
134
144
|
*
|
|
135
145
|
* These parameters are set per project in the `.storybook/preview.ts` file.
|
|
136
146
|
*/
|
|
137
|
-
|
|
147
|
+
interface VisOptions extends MatchImageSnapshotOptions, CustomizeSnapshotIdOptions {
|
|
138
148
|
/**
|
|
139
149
|
* The snapshot folder relative to the root of the project.
|
|
150
|
+
*
|
|
151
|
+
* Default: `__snapshots__/<local | CI platform>`
|
|
140
152
|
*/
|
|
141
|
-
snapshotPath
|
|
142
|
-
|
|
153
|
+
snapshotPath?: string | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Timeout for taking the snapshot.
|
|
156
|
+
*
|
|
157
|
+
* Default: 30000
|
|
158
|
+
*/
|
|
159
|
+
timeout?: number | undefined;
|
|
160
|
+
}
|
|
143
161
|
|
|
144
162
|
export { type CustomizeSnapshotIdOptions as C, type ImageSnapshotMatcher as I, type MatchImageSnapshotOptions as M, type VisOptions as V, commands as a, type ImageSnapshotOptions as b, cdp as c, type ImageSnapshot as d, page as p, server as s, toMatchImageSnapshot as t };
|
package/dist/vitest-setup.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { V as VisOptions } from './types-
|
|
2
|
-
export { I as ImageSnapshotMatcher, M as MatchImageSnapshotOptions, c as cdp, a as commands, p as page, s as server, t as toMatchImageSnapshot } from './types-
|
|
1
|
+
import { V as VisOptions } from './types-DtnVxcLK.js';
|
|
2
|
+
export { I as ImageSnapshotMatcher, M as MatchImageSnapshotOptions, c as cdp, a as commands, p as page, s as server, t as toMatchImageSnapshot } from './types-DtnVxcLK.js';
|
|
3
3
|
import '@vitest/browser/context';
|
|
4
|
+
import 'vitest';
|
|
4
5
|
import '@vitest/expect';
|
|
5
6
|
import 'pixelmatch';
|
|
6
|
-
import 'vitest';
|
|
7
7
|
|
|
8
8
|
declare function createVisConfig(options?: VisOptions): {
|
|
9
9
|
presets: {
|
package/dist/vitest-setup.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-
|
|
3
|
-
import { basename, join, dirname, relative } from 'pathe';
|
|
1
|
+
import { toMatchImageSnapshot, state, page } from './chunk-B2M7JPBQ.js';
|
|
2
|
+
export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-B2M7JPBQ.js';
|
|
4
3
|
import { expect } from 'vitest';
|
|
5
4
|
|
|
6
5
|
// src/should_take_snapshot.ts
|
|
7
6
|
function shouldTakeSnapshot() {
|
|
8
|
-
|
|
9
|
-
return state.tags.lastIndexOf("!snapshot") < state.tags.lastIndexOf("snapshot");
|
|
7
|
+
return state.shouldTakeSnapshot();
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
// src/vis.ts
|
|
11
|
+
expect.extend({ toMatchImageSnapshot });
|
|
13
12
|
function createVisConfig(options) {
|
|
14
|
-
expect.extend({ toMatchImageSnapshot });
|
|
15
13
|
const h = {
|
|
16
14
|
presets: {
|
|
17
15
|
basic() {
|
|
@@ -24,23 +22,7 @@ function createVisConfig(options) {
|
|
|
24
22
|
}
|
|
25
23
|
},
|
|
26
24
|
async beforeAll(suite) {
|
|
27
|
-
state.
|
|
28
|
-
state.testFilepath = suite.file.filepath;
|
|
29
|
-
state.testFilename = basename(state.testFilepath);
|
|
30
|
-
state.projectDir = state.testFilepath.slice(0, -state.name.length);
|
|
31
|
-
const snapshotPath = join(
|
|
32
|
-
state.projectDir,
|
|
33
|
-
options?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`
|
|
34
|
-
);
|
|
35
|
-
const currentDir = dirname(state.testFilepath);
|
|
36
|
-
state.baselineDir = relative(currentDir, join(snapshotPath, state.testFilename));
|
|
37
|
-
state.resultDir = relative(currentDir, join(snapshotPath, "__results__", state.testFilename));
|
|
38
|
-
state.diffDir = relative(currentDir, join(snapshotPath, "__diff_output__", state.testFilename));
|
|
39
|
-
if (!state.snapshot[state.testFilepath]) {
|
|
40
|
-
state.snapshot[state.testFilepath] = {};
|
|
41
|
-
await commands.rmDir(state.resultDir);
|
|
42
|
-
await commands.rmDir(state.diffDir);
|
|
43
|
-
}
|
|
25
|
+
return state.setupSuite(suite, options);
|
|
44
26
|
},
|
|
45
27
|
afterEach: {
|
|
46
28
|
async matchImageSnapshot() {
|
package/dist/vitest-setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/should_take_snapshot.ts","../src/vis.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/should_take_snapshot.ts","../src/vis.ts"],"names":[],"mappings":";;;;;AASO,SAAS,kBAAqB,GAAA;AACpC,EAAA,OAAO,MAAM,kBAAmB,EAAA;AACjC;;;ACHA,MAAO,CAAA,MAAA,CAAO,EAAE,oBAAA,EAAsB,CAAA;AAE/B,SAAS,gBAAgB,OAAsB,EAAA;AACrD,EAAA,MAAM,CAAI,GAAA;AAAA,IACT,OAAS,EAAA;AAAA,MACR,KAAQ,GAAA;AACP,QAAA,SAAA,CAAU,EAAE,SAAS,CAAA;AACrB,QAAU,SAAA,CAAA,CAAA,CAAE,UAAU,kBAAkB,CAAA;AAAA,OACzC;AAAA,MACA,MAAM,MAAoD,EAAA;AACzD,QAAA,SAAA,CAAU,EAAE,SAAS,CAAA;AACrB,QAAA,SAAA,CAAU,CAAE,CAAA,SAAA,CAAU,aAAc,CAAA,MAAM,CAAC,CAAA;AAAA;AAC5C,KACD;AAAA,IACA,MAAM,UAAU,KAAqD,EAAA;AACpE,MAAO,OAAA,KAAA,CAAM,UAAW,CAAA,KAAA,EAAO,OAAO,CAAA;AAAA,KACvC;AAAA,IACA,SAAW,EAAA;AAAA,MACV,MAAM,kBAAqB,GAAA;AAC1B,QAAI,IAAA,CAAC,oBAAsB,EAAA;AAC3B,QAAM,MAAA,CAAA,GAAI,MAAM,IAAA,CAAK,aAAc,EAAA;AACnC,QAAO,MAAA,CAAA,CAAC,EAAE,oBAAqB,EAAA;AAAA,OAChC;AAAA,MACA,cAAc,MAAoD,EAAA;AACjE,QAAA,OAAO,eAAe,kBAAqB,GAAA;AAC1C,UAAI,IAAA,CAAC,oBAAsB,EAAA;AAC3B,UAAA,KAAA,MAAW,WAAW,MAAQ,EAAA;AAC7B,YAAM,MAAA,MAAA,CAAO,OAAO,CAAE,EAAA;AACtB,YAAM,MAAA,CAAA,GAAI,MAAM,IAAA,CAAK,aAAc,CAAA;AAAA,cAClC,qBAAqB,CAAC,EAAA,KAAO,CAAG,EAAA,EAAE,IAAI,OAAO,CAAA;AAAA,aAC7C,CAAA;AACD,YAAM,MAAA,MAAA,CAAO,CAAC,CAAA,CAAE,oBAAqB,EAAA;AAAA;AACtC,SACD;AAAA;AACD;AACD,GACD;AACA,EAAO,OAAA,CAAA;AACR","file":"vitest-setup.js","sourcesContent":["import { state } from './state'\n\n/**\n * Determine should snapshot be taken.\n *\n * not story: false\n * no `snapshot` tag: false\n * disabled by `!snapshot` tag: false\n */\nexport function shouldTakeSnapshot() {\n\treturn state.shouldTakeSnapshot()\n}\n","import { expect } from 'vitest'\nimport { page } from './@vitest/browser/context.js'\nimport './augment.js'\nimport { toMatchImageSnapshot } from './expect.to_match_image_snapshot.js'\nimport { shouldTakeSnapshot } from './should_take_snapshot.js'\nimport { state } from './state.js'\nimport type { VisOptions } from './types.js'\n\nexpect.extend({ toMatchImageSnapshot })\n\nexport function createVisConfig(options?: VisOptions) {\n\tconst h = {\n\t\tpresets: {\n\t\t\tbasic() {\n\t\t\t\tbeforeAll(h.beforeAll)\n\t\t\t\tafterEach(h.afterEach.matchImageSnapshot)\n\t\t\t},\n\t\t\ttheme(themes: Record<string, () => void | Promise<void>>) {\n\t\t\t\tbeforeAll(h.beforeAll)\n\t\t\t\tafterEach(h.afterEach.matchPerTheme(themes))\n\t\t\t},\n\t\t},\n\t\tasync beforeAll(suite: { file: { filepath: string }; name: string }) {\n\t\t\treturn state.setupSuite(suite, options)\n\t\t},\n\t\tafterEach: {\n\t\t\tasync matchImageSnapshot() {\n\t\t\t\tif (!shouldTakeSnapshot()) return\n\t\t\t\tconst r = await page.imageSnapshot()\n\t\t\t\texpect(r).toMatchImageSnapshot()\n\t\t\t},\n\t\t\tmatchPerTheme(themes: Record<string, () => Promise<void> | void>) {\n\t\t\t\treturn async function matchImageSnapshot() {\n\t\t\t\t\tif (!shouldTakeSnapshot()) return\n\t\t\t\t\tfor (const themeId in themes) {\n\t\t\t\t\t\tawait themes[themeId]()\n\t\t\t\t\t\tconst r = await page.imageSnapshot({\n\t\t\t\t\t\t\tcustomizeSnapshotId: (id) => `${id}-${themeId}`,\n\t\t\t\t\t\t})\n\t\t\t\t\t\tawait expect(r).toMatchImageSnapshot()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t}\n\treturn h\n}\n"]}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -61,22 +61,30 @@ import * as projectAnnotations from './preview'
|
|
|
61
61
|
|
|
62
62
|
const project = setProjectAnnotations([projectAnnotations])
|
|
63
63
|
|
|
64
|
-
//
|
|
64
|
+
// capture image snapshot for all stories with `snapshot` tag
|
|
65
65
|
createVisConfig(/* options */).presets.basic()
|
|
66
|
+
|
|
67
|
+
// capture image snapshot for all stories with `snapshot` tag,
|
|
68
|
+
// for both light and dark themes
|
|
69
|
+
createVisConfig(/* options */).presets.theme({
|
|
70
|
+
light() { document.body.classList.remove('dark') },
|
|
71
|
+
dark() { document.body.classList.add('dark') },
|
|
72
|
+
})
|
|
66
73
|
```
|
|
67
74
|
|
|
68
|
-
On [storybook], you need to register
|
|
75
|
+
On [storybook], you need to register [storybook-addon-vis] in `.storybook/main.ts`.
|
|
69
76
|
|
|
70
77
|
```ts
|
|
71
|
-
// .storybook/
|
|
72
|
-
import { storybookPreviewVis } from 'storybook-addon-vis'
|
|
78
|
+
// .storybook/main.tsx
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
export default {
|
|
81
|
+
// ...
|
|
82
|
+
addons: [
|
|
83
|
+
// ...
|
|
84
|
+
'storybook-addon-vis'
|
|
85
|
+
]
|
|
75
86
|
// ...
|
|
76
|
-
beforeEach: storybookPreviewVis.beforeEach,
|
|
77
87
|
}
|
|
78
|
-
|
|
79
|
-
export default preview
|
|
80
88
|
```
|
|
81
89
|
|
|
82
90
|
## Usage - automatic snapshot
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { BrowserPage } from '@vitest/browser/context'
|
|
2
|
-
import { join } from 'pathe'
|
|
3
|
-
import { getCurrentTest } from 'vitest/suite'
|
|
4
2
|
import { toImageData } from '../../image_data.js'
|
|
5
3
|
import { state } from '../../state.js'
|
|
6
4
|
import { imageSnapshotSymbol } from './constants.js'
|
|
@@ -19,7 +17,7 @@ export async function imageSnapshot(
|
|
|
19
17
|
base64: true,
|
|
20
18
|
path: resultPath,
|
|
21
19
|
element: options?.element,
|
|
22
|
-
timeout: options?.timeout
|
|
20
|
+
timeout: state.getTimeout(options?.timeout),
|
|
23
21
|
})
|
|
24
22
|
state.incrementSnapshotIndex()
|
|
25
23
|
const image = await toImageData(screenshot.base64)
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { AsyncExpectationResult } from '@vitest/expect'
|
|
2
2
|
import dedent from 'dedent'
|
|
3
3
|
import pixelmatch, { type PixelmatchOptions } from 'pixelmatch'
|
|
4
|
-
import { required } from 'type-plus'
|
|
5
4
|
import { getCurrentTest } from 'vitest/suite'
|
|
6
5
|
import { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'
|
|
7
6
|
import { commands, page, server } from './@vitest/browser/context.js'
|
|
8
|
-
import { assertImageSnapshot, isImageSnapshot
|
|
7
|
+
import { assertImageSnapshot, isImageSnapshot } from './@vitest/browser/image_snapshot.logic.js'
|
|
9
8
|
import { toDataURL, toImageData } from './image_data.js'
|
|
10
9
|
import { createImageResizer } from './image_resizer.js'
|
|
11
10
|
import { state } from './state.js'
|
|
@@ -25,6 +24,11 @@ export type MatchImageSnapshotOptions = {
|
|
|
25
24
|
* Default is `pixel`.
|
|
26
25
|
*/
|
|
27
26
|
failureThresholdType?: 'pixel' | 'percent' | undefined
|
|
27
|
+
/**
|
|
28
|
+
* Failure tolerance threshold.
|
|
29
|
+
*
|
|
30
|
+
* Default is `0`.
|
|
31
|
+
*/
|
|
28
32
|
failureThreshold?: number | undefined
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -82,8 +86,11 @@ async function toMatchImageSnapshotInternal(
|
|
|
82
86
|
|
|
83
87
|
// const test = getCurrentTest()
|
|
84
88
|
// console.log('test', test)
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
const { pass, diffAmount, diffImage } = compareImage(
|
|
90
|
+
baselineImage,
|
|
91
|
+
resultImage,
|
|
92
|
+
state.mergeMatchImageSnapshotOptions(options),
|
|
93
|
+
)
|
|
87
94
|
|
|
88
95
|
if (!pass) {
|
|
89
96
|
if (server.config.snapshotOptions.updateSnapshot === 'all') {
|
|
@@ -94,7 +101,7 @@ async function toMatchImageSnapshotInternal(
|
|
|
94
101
|
return {
|
|
95
102
|
pass: false,
|
|
96
103
|
message: () =>
|
|
97
|
-
dedent`Snapshot \`${state.
|
|
104
|
+
dedent`Snapshot \`${state.getName()}\` mismatched
|
|
98
105
|
|
|
99
106
|
${
|
|
100
107
|
options?.failureThreshold
|
|
@@ -8,6 +8,5 @@ import { state } from './state'
|
|
|
8
8
|
* disabled by `!snapshot` tag: false
|
|
9
9
|
*/
|
|
10
10
|
export function shouldTakeSnapshot() {
|
|
11
|
-
|
|
12
|
-
return state.tags.lastIndexOf('!snapshot') < state.tags.lastIndexOf('snapshot')
|
|
11
|
+
return state.shouldTakeSnapshot()
|
|
13
12
|
}
|
package/src/state.ts
CHANGED
|
@@ -1,53 +1,94 @@
|
|
|
1
|
-
import { join } from 'pathe'
|
|
1
|
+
import { basename, dirname, join, relative } from 'pathe'
|
|
2
|
+
import type { StoryContext } from 'storybook/internal/types'
|
|
3
|
+
import { omit, required } from 'type-plus'
|
|
2
4
|
import { getCurrentTest } from 'vitest/suite'
|
|
5
|
+
import { commands } from './@vitest/browser/context.js'
|
|
3
6
|
import { toSnapshotId } from './@vitest/browser/image_snapshot.logic'
|
|
4
7
|
import type { ImageSnapshotOptions } from './@vitest/browser/types'
|
|
5
8
|
import type { MatchImageSnapshotOptions } from './expect.to_match_image_snapshot'
|
|
9
|
+
import type { VisOptions } from './types.js'
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
function createStore() {
|
|
12
|
+
// test suite (runner.beforeAll) states
|
|
13
|
+
let name: string
|
|
14
|
+
let testFilepath: string
|
|
15
|
+
let testFilename: string
|
|
16
|
+
let baselineDir: string
|
|
17
|
+
let resultDir: string
|
|
18
|
+
let diffDir: string
|
|
19
|
+
let snapshot: Record<string, Record<string, { index: number }>>
|
|
20
|
+
let suiteOptions: VisOptions = {}
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
22
|
+
// story states (story.beforeEach)
|
|
23
|
+
let tags: string[] | undefined
|
|
24
|
+
let parameters: Record<string, any> | undefined
|
|
25
|
+
let taskName: string
|
|
26
|
+
let id: string
|
|
27
|
+
|
|
28
|
+
const state = {
|
|
29
|
+
baselineDir,
|
|
30
|
+
resultDir,
|
|
31
|
+
diffDir,
|
|
32
|
+
snapshot: {},
|
|
33
|
+
async setupSuite(suite: { file: { filepath: string }; name: string }, options?: VisOptions) {
|
|
34
|
+
name = suite.name
|
|
35
|
+
testFilepath = suite.file.filepath
|
|
36
|
+
testFilename = basename(testFilepath)
|
|
37
|
+
const projectDir = testFilepath.slice(0, -name.length)
|
|
38
|
+
const snapshotPath = join(
|
|
39
|
+
projectDir,
|
|
40
|
+
options?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`,
|
|
41
|
+
)
|
|
42
|
+
const currentDir = dirname(testFilepath)
|
|
43
|
+
baselineDir = relative(currentDir, join(snapshotPath, testFilename))
|
|
44
|
+
resultDir = relative(currentDir, join(snapshotPath, '__results__', testFilename))
|
|
45
|
+
diffDir = relative(currentDir, join(snapshotPath, '__diff_output__', testFilename))
|
|
46
|
+
|
|
47
|
+
suiteOptions = options ?? {}
|
|
48
|
+
snapshot = snapshot ?? {}
|
|
49
|
+
if (!snapshot[testFilepath]) {
|
|
50
|
+
snapshot[testFilepath] = {}
|
|
51
|
+
await commands.rmDir(resultDir)
|
|
52
|
+
await commands.rmDir(diffDir)
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
setupStory(ctx: StoryContext) {
|
|
56
|
+
tags = ctx.tags
|
|
57
|
+
parameters = ctx.parameters
|
|
58
|
+
},
|
|
59
|
+
shouldTakeSnapshot() {
|
|
60
|
+
if (!tags) return false
|
|
61
|
+
return tags.lastIndexOf('!snapshot') < tags.lastIndexOf('snapshot')
|
|
62
|
+
},
|
|
63
|
+
getName() {
|
|
64
|
+
return taskName
|
|
65
|
+
},
|
|
66
|
+
getTimeout(timeout?: number | undefined) {
|
|
67
|
+
return timeout ?? suiteOptions.timeout ?? 30000
|
|
68
|
+
},
|
|
69
|
+
mergeMatchImageSnapshotOptions(options?: MatchImageSnapshotOptions) {
|
|
70
|
+
return required(omit(suiteOptions, 'snapshotPath'), parameters?.snapshot, options)
|
|
71
|
+
},
|
|
72
|
+
getSnapshotFilePaths(options?: ImageSnapshotOptions | undefined) {
|
|
73
|
+
const test = getCurrentTest()
|
|
74
|
+
taskName = test.name
|
|
75
|
+
id = toSnapshotId(taskName)
|
|
76
|
+
snapshot[testFilepath][id] = snapshot[testFilepath][id] ?? { index: 1 }
|
|
77
|
+
|
|
78
|
+
const index = snapshot[testFilepath][id]!.index
|
|
79
|
+
const customizeSnapshotId =
|
|
80
|
+
suiteOptions.customizeSnapshotId ?? options?.customizeSnapshotId ?? ((id, index) => `${id}-${index}`)
|
|
81
|
+
const snapshotFilename = `${customizeSnapshotId(id, index)}.png`
|
|
82
|
+
const baselinePath = join(baselineDir, snapshotFilename)
|
|
83
|
+
const resultPath = join(resultDir, snapshotFilename)
|
|
84
|
+
const diffPath = join(diffDir, snapshotFilename)
|
|
85
|
+
return { snapshotFilename, baselinePath, resultPath, diffPath }
|
|
86
|
+
},
|
|
87
|
+
incrementSnapshotIndex() {
|
|
88
|
+
snapshot[testFilepath][id]!.index++
|
|
89
|
+
},
|
|
51
90
|
}
|
|
52
|
-
|
|
91
|
+
return state
|
|
53
92
|
}
|
|
93
|
+
|
|
94
|
+
export const state = createStore()
|
package/src/storybook/preview.ts
CHANGED
|
@@ -3,14 +3,14 @@ import type { ProjectAnnotations, Renderer, StoryContext } from 'storybook/inter
|
|
|
3
3
|
import { toMatchImageSnapshot } from '../expect.to_match_image_snapshot'
|
|
4
4
|
import { state } from '../state'
|
|
5
5
|
|
|
6
|
+
expect.extend({ toMatchImageSnapshot })
|
|
7
|
+
|
|
6
8
|
export const storybookPreviewVis = defineVisPreview()
|
|
7
9
|
|
|
8
|
-
export function defineVisPreview<R extends Renderer>()
|
|
9
|
-
expect.extend({ toMatchImageSnapshot })
|
|
10
|
+
export function defineVisPreview<R extends Renderer>() {
|
|
10
11
|
return {
|
|
11
12
|
beforeEach(ctx: StoryContext) {
|
|
12
|
-
state.
|
|
13
|
-
state.parameters = ctx.parameters
|
|
13
|
+
return state.setupStory(ctx)
|
|
14
14
|
},
|
|
15
|
-
}
|
|
15
|
+
} satisfies ProjectAnnotations<R>
|
|
16
16
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
|
+
import type { CustomizeSnapshotIdOptions } from './@vitest/browser/types'
|
|
2
|
+
import type { MatchImageSnapshotOptions } from './expect.to_match_image_snapshot'
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* The project parameters for the snapshot.
|
|
3
6
|
*
|
|
4
7
|
* These parameters are set per project in the `.storybook/preview.ts` file.
|
|
5
8
|
*/
|
|
6
|
-
export
|
|
9
|
+
export interface VisOptions extends MatchImageSnapshotOptions, CustomizeSnapshotIdOptions {
|
|
7
10
|
/**
|
|
8
11
|
* The snapshot folder relative to the root of the project.
|
|
12
|
+
*
|
|
13
|
+
* Default: `__snapshots__/<local | CI platform>`
|
|
9
14
|
*/
|
|
10
|
-
snapshotPath
|
|
15
|
+
snapshotPath?: string | undefined
|
|
16
|
+
/**
|
|
17
|
+
* Timeout for taking the snapshot.
|
|
18
|
+
*
|
|
19
|
+
* Default: 30000
|
|
20
|
+
*/
|
|
21
|
+
timeout?: number | undefined
|
|
11
22
|
}
|
package/src/vis.spec.ts
CHANGED
|
@@ -5,9 +5,42 @@ it('can define the snapshot root folder relative to the root of the project', as
|
|
|
5
5
|
await createVisConfig({
|
|
6
6
|
snapshotPath: '_sp_',
|
|
7
7
|
}).beforeAll({ name: 'some.test.ts', file: { filepath: 'dummy/some.test.ts' } }),
|
|
8
|
-
expect(state).toMatchObject({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
expect(state.getSnapshotFilePaths()).toMatchObject({
|
|
9
|
+
baselinePath: '_sp_/some.test.ts/can-define-the-snapshot-root-folder-relative-to-the-root-of-the-project-1.png',
|
|
10
|
+
diffPath:
|
|
11
|
+
'_sp_/__diff_output__/some.test.ts/can-define-the-snapshot-root-folder-relative-to-the-root-of-the-project-1.png',
|
|
12
|
+
resultPath:
|
|
13
|
+
'_sp_/__results__/some.test.ts/can-define-the-snapshot-root-folder-relative-to-the-root-of-the-project-1.png',
|
|
12
14
|
})
|
|
13
15
|
})
|
|
16
|
+
|
|
17
|
+
it('can define the timeout value for taking the snapshot', async () => {
|
|
18
|
+
await createVisConfig({
|
|
19
|
+
timeout: 30000,
|
|
20
|
+
}).beforeAll({ name: 'some.test.ts', file: { filepath: 'dummy/some.test.ts' } })
|
|
21
|
+
|
|
22
|
+
expect(state.getTimeout()).toEqual(30000)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('can define default failureThreshold', async () => {
|
|
26
|
+
await createVisConfig({
|
|
27
|
+
failureThreshold: 50,
|
|
28
|
+
}).beforeAll({ name: 'some.test.ts', file: { filepath: 'dummy/some.test.ts' } })
|
|
29
|
+
|
|
30
|
+
expect(state.mergeMatchImageSnapshotOptions()).toMatchObject({
|
|
31
|
+
failureThreshold: 50,
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('can define default failureThresholdType', async () => {
|
|
36
|
+
await createVisConfig({
|
|
37
|
+
snapshotPath: '_sp_',
|
|
38
|
+
customizeSnapshotId: (id) => id.slice(0, id.indexOf('-')),
|
|
39
|
+
}).beforeAll({ name: 'some.test.ts', file: { filepath: 'dummy/some.test.ts' } })
|
|
40
|
+
|
|
41
|
+
expect(state.getSnapshotFilePaths()).toMatchObject({
|
|
42
|
+
baselinePath: '_sp_/some.test.ts/can.png',
|
|
43
|
+
diffPath: '_sp_/__diff_output__/some.test.ts/can.png',
|
|
44
|
+
resultPath: '_sp_/__results__/some.test.ts/can.png',
|
|
45
|
+
})
|
|
46
|
+
})
|
package/src/vis.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { basename, dirname, join, relative } from 'pathe'
|
|
2
1
|
import { expect } from 'vitest'
|
|
3
|
-
import {
|
|
2
|
+
import { page } from './@vitest/browser/context.js'
|
|
4
3
|
import './augment.js'
|
|
5
4
|
import { toMatchImageSnapshot } from './expect.to_match_image_snapshot.js'
|
|
6
5
|
import { shouldTakeSnapshot } from './should_take_snapshot.js'
|
|
7
6
|
import { state } from './state.js'
|
|
8
7
|
import type { VisOptions } from './types.js'
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
expect.extend({ toMatchImageSnapshot })
|
|
9
|
+
expect.extend({ toMatchImageSnapshot })
|
|
12
10
|
|
|
11
|
+
export function createVisConfig(options?: VisOptions) {
|
|
13
12
|
const h = {
|
|
14
13
|
presets: {
|
|
15
14
|
basic() {
|
|
@@ -22,24 +21,7 @@ export function createVisConfig(options?: VisOptions) {
|
|
|
22
21
|
},
|
|
23
22
|
},
|
|
24
23
|
async beforeAll(suite: { file: { filepath: string }; name: string }) {
|
|
25
|
-
state.
|
|
26
|
-
state.testFilepath = suite.file.filepath
|
|
27
|
-
state.testFilename = basename(state.testFilepath)
|
|
28
|
-
state.projectDir = state.testFilepath.slice(0, -state.name.length)
|
|
29
|
-
const snapshotPath = join(
|
|
30
|
-
state.projectDir,
|
|
31
|
-
options?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`,
|
|
32
|
-
)
|
|
33
|
-
const currentDir = dirname(state.testFilepath)
|
|
34
|
-
state.baselineDir = relative(currentDir, join(snapshotPath, state.testFilename))
|
|
35
|
-
state.resultDir = relative(currentDir, join(snapshotPath, '__results__', state.testFilename))
|
|
36
|
-
state.diffDir = relative(currentDir, join(snapshotPath, '__diff_output__', state.testFilename))
|
|
37
|
-
|
|
38
|
-
if (!state.snapshot[state.testFilepath]) {
|
|
39
|
-
state.snapshot[state.testFilepath] = {}
|
|
40
|
-
await commands.rmDir(state.resultDir)
|
|
41
|
-
await commands.rmDir(state.diffDir)
|
|
42
|
-
}
|
|
24
|
+
return state.setupSuite(suite, options)
|
|
43
25
|
},
|
|
44
26
|
afterEach: {
|
|
45
27
|
async matchImageSnapshot() {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/@vitest/browser/constants.ts","../src/@vitest/browser/image_snapshot.logic.ts","../src/state.ts","../src/@vitest/browser/page.has_image_snapshot.ts","../src/image_data.ts","../src/@vitest/browser/page.image_snapshot.ts","../src/@vitest/browser/context.ts","../src/image_resizer.ts","../src/expect.to_match_image_snapshot.ts"],"names":["ctx","getCurrentTest"],"mappings":"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","file":"chunk-EYGWSOX2.js","sourcesContent":["export const imageSnapshotSymbol = Symbol.for('storybook-addon-vis/imageSnapshot')\n\nexport const imageSnapshotStubSymbol = Symbol.for('storybook-addon-vis/imageSnapshotStub')\n","import { imageSnapshotSymbol } from './constants.js'\nimport type { ImageSnapshot } from './types.js'\n\nexport function isImageSnapshot(subject: any): subject is ImageSnapshot {\n\treturn !!subject && subject.type === imageSnapshotSymbol\n}\n\nexport function assertImageSnapshot(subject: any): asserts subject is ImageSnapshot {\n\tif (!isImageSnapshot(subject)) {\n\t\tthrow new Error('Expected subject to be an image snapshot')\n\t}\n}\n\nexport function toSnapshotId(taskName: string) {\n\treturn `${taskName.replace(/[^a-z0-9]/gi, '-').toLowerCase()}`\n}\n","import { join } from 'pathe'\nimport { getCurrentTest } from 'vitest/suite'\nimport { toSnapshotId } from './@vitest/browser/image_snapshot.logic'\nimport type { ImageSnapshotOptions } from './@vitest/browser/types'\nimport type { MatchImageSnapshotOptions } from './expect.to_match_image_snapshot'\n\nexport const state = {\n\tname: '',\n\ttestFilepath: '',\n\ttaskName: '',\n\tsnapshot: {},\n\tgetSnapshotFilePaths(options?: ImageSnapshotOptions | undefined) {\n\t\tconst test = getCurrentTest()\n\t\tstate.taskName = test.name\n\t\tconst id = (state.id = toSnapshotId(state.taskName))\n\t\tstate.snapshot[state.testFilepath][id] = state.snapshot[state.testFilepath][id] ?? { index: 1 }\n\n\t\tconst index = state.snapshot[state.testFilepath][state.id]!.index\n\t\tconst snapshotFilename = options?.customizeSnapshotId\n\t\t\t? `${options.customizeSnapshotId(state.id, index)}.png`\n\t\t\t: `${state.id}-${index}.png`\n\t\tconst baselinePath = join(state.baselineDir, snapshotFilename)\n\t\tconst resultPath = join(state.resultDir, snapshotFilename)\n\t\tconst diffPath = join(state.diffDir, snapshotFilename)\n\t\treturn { snapshotFilename, baselinePath, resultPath, diffPath }\n\t},\n\tincrementSnapshotIndex() {\n\t\tstate.snapshot[state.testFilepath][state.id]!.index++\n\t},\n} as unknown as {\n\tid: string\n\tname: string\n\ttestFilepath: string\n\ttestFilename: string\n\tprojectDir: string\n\tbaselineDir: string\n\tresultDir: string\n\tdiffDir: string\n\ttaskName: string\n\tparameters: {\n\t\tsnapshot?: MatchImageSnapshotOptions | undefined\n\t\t[key: string]: any\n\t}\n\ttags: string[]\n\tsnapshot: Record<string, Record<string, { index: number }>>\n\tgetSnapshotFilePaths(options?: ImageSnapshotOptions | undefined): {\n\t\tsnapshotFilename: string\n\t\tbaselinePath: string\n\t\tresultPath: string\n\t\tdiffPath: string\n\t}\n\tincrementSnapshotIndex(): void\n}\n","import type { BrowserPage } from '@vitest/browser/context'\nimport { join } from 'pathe'\nimport { state } from '../../state'\nimport { commands } from './context'\nimport type { CustomizeSnapshotIdOptions } from './types'\n\nexport interface HasImageSnapshotAction {\n\thasImageSnapshot(this: BrowserPage, options?: CustomizeSnapshotIdOptions | undefined): Promise<boolean>\n}\n\n/**\n * Check if the snapshot image exists.\n */\nexport async function hasImageSnapshot(this: BrowserPage, options?: CustomizeSnapshotIdOptions | undefined) {\n\tconst { baselinePath } = state.getSnapshotFilePaths(options)\n\treturn commands.existFile(baselinePath)\n}\n","export function toImageData(base64: string) {\n\treturn new Promise<ImageData>((resolve, reject) => {\n\t\tconst img = new Image()\n\t\timg.src = `data:image/png;base64,${base64}`\n\n\t\timg.onload = () => {\n\t\t\tconst canvas = document.createElement('canvas')\n\t\t\tcanvas.width = img.width\n\t\t\tcanvas.height = img.height\n\t\t\tconst ctx = canvas.getContext('2d')!\n\t\t\tctx.drawImage(img, 0, 0)\n\t\t\tresolve(ctx.getImageData(0, 0, canvas.width, canvas.height))\n\t\t}\n\n\t\timg.onerror = () => {\n\t\t\treject(new Error('Failed to load image'))\n\t\t}\n\t})\n}\n\nexport async function toDataURL(imageData: ImageData) {\n\tconst canvas = document.createElement('canvas')\n\tcanvas.width = imageData.width\n\tcanvas.height = imageData.height\n\tconst ctx = canvas.getContext('2d')!\n\tctx.putImageData(imageData, 0, 0)\n\treturn new Promise<string>((resolve) => {\n\t\tcanvas.toBlob((blob) => {\n\t\t\tconst reader = new FileReader()\n\t\t\treader.onload = () => {\n\t\t\t\tresolve(reader.result as string)\n\t\t\t}\n\t\t\treader.readAsDataURL(blob!)\n\t\t})\n\t})\n}\n","import type { BrowserPage } from '@vitest/browser/context'\nimport { join } from 'pathe'\nimport { getCurrentTest } from 'vitest/suite'\nimport { toImageData } from '../../image_data.js'\nimport { state } from '../../state.js'\nimport { imageSnapshotSymbol } from './constants.js'\nimport type { ImageSnapshot, ImageSnapshotOptions } from './types.js'\n\nexport interface ImageSnapshotAction {\n\timageSnapshot(this: BrowserPage, options?: ImageSnapshotOptions | undefined): Promise<ImageSnapshot>\n}\n\nexport async function imageSnapshot(\n\tthis: BrowserPage,\n\toptions?: ImageSnapshotOptions | undefined,\n): Promise<ImageSnapshot> {\n\tconst { snapshotFilename, baselinePath, resultPath, diffPath } = state.getSnapshotFilePaths(options)\n\tconst screenshot = await this.screenshot({\n\t\tbase64: true,\n\t\tpath: resultPath,\n\t\telement: options?.element,\n\t\ttimeout: options?.timeout ?? 3000,\n\t})\n\tstate.incrementSnapshotIndex()\n\tconst image = await toImageData(screenshot.base64)\n\n\treturn {\n\t\ttype: imageSnapshotSymbol,\n\t\tsnapshotFilename,\n\t\tbaselinePath,\n\t\tresultPath,\n\t\tdiffPath,\n\t\tbase64: screenshot.base64,\n\t\timage,\n\t}\n}\n","import {\n\tgetByAltText,\n\tgetByLabelText,\n\tgetByPlaceholderText,\n\tgetByRole,\n\tgetByTestId,\n\tgetByText,\n\tgetByTitle,\n} from '@storybook/test'\nimport type { BrowserCommands, BrowserPage, CDPSession, Platform } from '@vitest/browser/context'\nimport type { SerializedConfig } from 'vitest'\nimport { imageSnapshotStubSymbol } from './constants'\nimport { hasImageSnapshot } from './page.has_image_snapshot'\nimport { imageSnapshot } from './page.image_snapshot'\n\nlet ctx: Awaited<typeof import('@vitest/browser/context')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('@vitest/browser/context').then((m) => {\n\t\tctx = m\n\t\tpage.extend({ imageSnapshot, hasImageSnapshot })\n\t})\n}\n\n// TODO: stub the functions within the `CDPSession`\n// when we better understands the use cases\nexport function cdp(): CDPSession {\n\treturn ctx?.cdp() ?? ({} as any)\n}\n\nexport const commands = new Proxy<BrowserCommands>({} as any, {\n\tget(target, prop) {\n\t\treturn (target as any)[prop] ?? (ctx?.commands as any)[prop]\n\t},\n})\n\nexport const page = new Proxy<BrowserPage>(\n\t{\n\t\tgetByAltText,\n\t\tgetByRole,\n\t\tgetByTestId,\n\t\tgetByText,\n\t\tgetByTitle,\n\t\tgetByPlaceholder: getByPlaceholderText,\n\t\tgetByLabelText,\n\t} as any,\n\t{\n\t\tget(target, prop) {\n\t\t\treturn ((target as any)[prop] ?? ctx?.page)\n\t\t\t\t? (ctx?.page as any)[prop]\n\t\t\t\t: () => {\n\t\t\t\t\t\tif (prop === 'imageSnapshot') {\n\t\t\t\t\t\t\treturn { type: imageSnapshotStubSymbol }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (prop === 'hasImageSnapshot') {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.info(`\\`page.${prop.toString()}\\` does not exist when running in browser`)\n\t\t\t\t\t}\n\t\t},\n\t},\n)\n\nexport const server = new Proxy<{\n\t/**\n\t * Platform the Vitest server is running on.\n\t * The same as calling `process.platform` on the server.\n\t */\n\tplatform: Platform\n\t/**\n\t * Runtime version of the Vitest server.\n\t * The same as calling `process.version` on the server.\n\t */\n\tversion: string\n\t/**\n\t * Name of the browser provider.\n\t */\n\tprovider: string\n\t/**\n\t * Name of the current browser.\n\t */\n\tbrowser: string\n\t/**\n\t * Available commands for the browser.\n\t * @see {@link https://vitest.dev/guide/browser/commands}\n\t */\n\tcommands: BrowserCommands\n\t/**\n\t * Serialized test config.\n\t */\n\tconfig: SerializedConfig\n}>({} as any, {\n\tget(target, prop) {\n\t\treturn (target as any)[prop] ?? (ctx?.server as any)[prop]\n\t},\n})\n","export const createImageResizer =\n\t({ width, height }: { width: number; height: number }) =>\n\t(image: ImageData) => {\n\t\tif (image.width === width && image.height === height) {\n\t\t\treturn image\n\t\t}\n\t\tconst inArea = (x: number, y: number) => y <= image.height && x <= image.width\n\t\tconst result = new ImageData(width, height, { colorSpace: image.colorSpace })\n\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst idx = (width * y + x) << 2\n\t\t\t\tif (inArea(x, y)) {\n\t\t\t\t\tconst old = (image.width * y + x) << 2\n\t\t\t\t\tresult.data[idx] = image.data[old]\n\t\t\t\t\tresult.data[idx + 1] = image.data[old + 1]\n\t\t\t\t\tresult.data[idx + 2] = image.data[old + 2]\n\t\t\t\t\tresult.data[idx + 3] = image.data[old + 3]\n\t\t\t\t} else {\n\t\t\t\t\tresult.data[idx] = 0\n\t\t\t\t\tresult.data[idx + 1] = 0\n\t\t\t\t\tresult.data[idx + 2] = 0\n\t\t\t\t\tresult.data[idx + 3] = 64\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n\n// slower\nexport const createImageResizer2 =\n\t({ width, height }: { width: number; height: number }) =>\n\t(image: ImageData) => {\n\t\tif (image.width === width && image.height === height) {\n\t\t\treturn image\n\t\t}\n\t\tconst inArea = (x: number, y: number) => y <= image.height && x <= image.width\n\t\tconst result = new ImageData(width, height, { colorSpace: image.colorSpace })\n\n\t\tconst copyBytes = image.width * 4\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tresult.data.set(image.data.slice(y * image.width, copyBytes), y * width * 4)\n\t\t\tfor (let x = image.width; x < width; x++) {\n\t\t\t\tconst idx = (width * y + x) << 2\n\t\t\t\tif (!inArea(x, y)) {\n\t\t\t\t\tresult.data[idx] = 0\n\t\t\t\t\tresult.data[idx + 1] = 0\n\t\t\t\t\tresult.data[idx + 2] = 0\n\t\t\t\t\tresult.data[idx + 3] = 64\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n","import type { AsyncExpectationResult } from '@vitest/expect'\nimport dedent from 'dedent'\nimport pixelmatch, { type PixelmatchOptions } from 'pixelmatch'\nimport { required } from 'type-plus'\nimport { getCurrentTest } from 'vitest/suite'\nimport { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'\nimport { commands, page, server } from './@vitest/browser/context.js'\nimport { assertImageSnapshot, isImageSnapshot, toSnapshotId } from './@vitest/browser/image_snapshot.logic.js'\nimport { toDataURL, toImageData } from './image_data.js'\nimport { createImageResizer } from './image_resizer.js'\nimport { state } from './state.js'\n\nexport interface ImageSnapshotMatcher {\n\ttoMatchImageSnapshot(options?: MatchImageSnapshotOptions): Promise<void>\n}\n\nexport type MatchImageSnapshotOptions = {\n\t/**\n\t * Custom options passed to 'pixelmatch'\n\t */\n\tdiffOptions?: PixelmatchOptions | undefined\n\t/**\n\t * Failure threshold should measure in `pixel` or `percent`.\n\t *\n\t * Default is `pixel`.\n\t */\n\tfailureThresholdType?: 'pixel' | 'percent' | undefined\n\tfailureThreshold?: number | undefined\n}\n\nexport async function toMatchImageSnapshot(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tconst promise = toMatchImageSnapshotInternal(actual, options)\n\tconst test = getCurrentTest()\n\tif (!test) return promise\n\ttest.promises ??= []\n\ttest.promises.push(promise)\n\treturn promise\n}\n\nasync function toMatchImageSnapshotInternal(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tlet subject = await actual\n\tif (subject?.type === imageSnapshotStubSymbol) {\n\t\treturn success\n\t}\n\tif (!isImageSnapshot(subject)) {\n\t\tif (subject?.path && subject?.base64) {\n\t\t\treturn {\n\t\t\t\tpass: false,\n\t\t\t\tactual: subject,\n\t\t\t\tmessage: () =>\n\t\t\t\t\t'`toMatchImageSnapshot()` expects the subject to be the result of `page.imageSnapshot()`, but seems like you are using `page.screenshot()`?',\n\t\t\t}\n\t\t}\n\n\t\tif (typeof subject !== 'object') {\n\t\t\treturn {\n\t\t\t\tpass: false,\n\t\t\t\tactual: subject,\n\t\t\t\tmessage: () =>\n\t\t\t\t\t`\\`toMatchImageSnapshot()\\` expects the subject to be an element, locator, or result of \\`page.imageSnapshot()\\`, but got: \\`${subject}\\``,\n\t\t\t}\n\t\t}\n\t\tsubject = await page.imageSnapshot({ element: subject })\n\t}\n\n\tassertImageSnapshot(subject)\n\n\tconst baseline = await tryReadSnapshot(subject.baselinePath)\n\tif (!baseline) {\n\t\tawait commands.copyFile(subject.resultPath, subject.baselinePath)\n\t\treturn success\n\t}\n\n\tconst originalImage = await toImageData(baseline)\n\tconst [resultImage, baselineImage] = alignImagesToSameSize(subject.image, originalImage)\n\n\t// const test = getCurrentTest()\n\t// console.log('test', test)\n\toptions = required(state.parameters?.snapshot, options)\n\tconst { pass, diffAmount, diffImage } = compareImage(baselineImage, resultImage, options)\n\n\tif (!pass) {\n\t\tif (server.config.snapshotOptions.updateSnapshot === 'all') {\n\t\t\tawait writeSnapshot(`${subject.baselinePath}`, resultImage)\n\t\t\treturn success\n\t\t}\n\t\tawait writeSnapshot(`${subject.diffPath}`, diffImage)\n\t\treturn {\n\t\t\tpass: false,\n\t\t\tmessage: () =>\n\t\t\t\tdedent`Snapshot \\`${state.taskName}\\` mismatched\n\n\t\t\t${\n\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\t\t\t\t\t? `Expected image to match within ${options.failureThreshold}% but was differ by ${diffAmount}%.`\n\t\t\t\t\t\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\t\t}\n\n\t\t\tExpected: '${subject.baselinePath}'\n\t\t\tActual: '${subject.resultPath}'\n\t\t\tDifference: '${subject.diffPath}'`,\n\t\t}\n\t}\n\treturn success\n}\n\nconst success = {\n\tpass: true,\n\tmessage: () => '',\n}\n\nfunction tryReadSnapshot(path: string): Promise<string | undefined> {\n\treturn commands.readFile(path, { encoding: 'base64' }).catch(() => undefined)\n}\nasync function writeSnapshot(path: string, image: ImageData) {\n\tconst content = (await toDataURL(image)).split(',')[1]!\n\treturn commands.writeFile(path, content, 'base64url')\n}\n\nfunction alignImagesToSameSize(image1: ImageData, image2: ImageData): [image1: ImageData, image2: ImageData] {\n\tif (isSameSize(image1, image2)) {\n\t\treturn [image1, image2]\n\t}\n\tconst size = getMaxSize(image1, image2)\n\tconst resize = createImageResizer(size)\n\treturn [resize(image1), resize(image2)]\n}\n\nfunction getMaxSize(image1: ImageData, image2: ImageData) {\n\tconst width = Math.max(image1.width, image2.width)\n\tconst height = Math.max(image1.height, image2.height)\n\treturn { width, height }\n}\n\nfunction isSameSize(image1: ImageData, image2: ImageData) {\n\treturn image1.width === image2.width && image1.height === image2.height\n}\n\nfunction compareImage(\n\tbaselineImage: ImageData,\n\tresultImage: ImageData,\n\t{ failureThreshold = 0, failureThresholdType = 'pixel', diffOptions }: MatchImageSnapshotOptions = {},\n) {\n\tconst { width, height } = resultImage\n\tconst diffImage = new ImageData(width, height)\n\n\tconst pixelDiff = pixelmatch(resultImage.data, baselineImage.data, diffImage.data, width, height, diffOptions)\n\tconst diffAmount = toThresholdUnit({ failureThresholdType, width, height }, pixelDiff)\n\n\treturn {\n\t\tpass: diffAmount <= failureThreshold,\n\t\tdiffAmount,\n\t\tdiffImage,\n\t}\n}\n\nfunction toThresholdUnit(\n\t{ failureThresholdType, width, height }: { failureThresholdType: 'pixel' | 'percent'; width: number; height: number },\n\tpixelDiff: number,\n): number {\n\tswitch (failureThresholdType) {\n\t\tcase 'pixel':\n\t\t\treturn pixelDiff\n\t\tcase 'percent':\n\t\t\treturn (pixelDiff / (width * height)) * 100\n\t\tdefault:\n\t\t\tthrow new Error(`Invalid failureThresholdType: ${failureThresholdType}`)\n\t}\n}\n"]}
|
package/dist/chunk-FLRCYKBG.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { toMatchImageSnapshot, state } from './chunk-EYGWSOX2.js';
|
|
2
|
-
import { expect } from '@storybook/test';
|
|
3
|
-
|
|
4
|
-
var storybookPreviewVis = defineVisPreview();
|
|
5
|
-
function defineVisPreview() {
|
|
6
|
-
expect.extend({ toMatchImageSnapshot });
|
|
7
|
-
return {
|
|
8
|
-
beforeEach(ctx) {
|
|
9
|
-
state.tags = ctx.tags;
|
|
10
|
-
state.parameters = ctx.parameters;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export { defineVisPreview, storybookPreviewVis };
|
|
16
|
-
//# sourceMappingURL=chunk-FLRCYKBG.js.map
|
|
17
|
-
//# sourceMappingURL=chunk-FLRCYKBG.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/storybook/preview.ts"],"names":[],"mappings":";;;AAKO,IAAM,sBAAsB,gBAAiB;AAE7C,SAAS,gBAA8D,GAAA;AAC7E,EAAO,MAAA,CAAA,MAAA,CAAO,EAAE,oBAAA,EAAsB,CAAA;AACtC,EAAO,OAAA;AAAA,IACN,WAAW,GAAmB,EAAA;AAC7B,MAAA,KAAA,CAAM,OAAO,GAAI,CAAA,IAAA;AACjB,MAAA,KAAA,CAAM,aAAa,GAAI,CAAA,UAAA;AAAA;AACxB,GACD;AACD","file":"chunk-FLRCYKBG.js","sourcesContent":["import { expect } from '@storybook/test'\nimport type { ProjectAnnotations, Renderer, StoryContext } from 'storybook/internal/types'\nimport { toMatchImageSnapshot } from '../expect.to_match_image_snapshot'\nimport { state } from '../state'\n\nexport const storybookPreviewVis = defineVisPreview()\n\nexport function defineVisPreview<R extends Renderer>(): ProjectAnnotations<R> {\n\texpect.extend({ toMatchImageSnapshot })\n\treturn {\n\t\tbeforeEach(ctx: StoryContext) {\n\t\t\tstate.tags = ctx.tags\n\t\t\tstate.parameters = ctx.parameters\n\t\t},\n\t}\n}\n"]}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { ProjectAnnotations, Renderer } from 'storybook/internal/types';
|
|
2
|
-
|
|
3
|
-
declare const storybookPreviewVis: ProjectAnnotations<Renderer>;
|
|
4
|
-
declare function defineVisPreview<R extends Renderer>(): ProjectAnnotations<R>;
|
|
5
|
-
|
|
6
|
-
export { defineVisPreview as d, storybookPreviewVis as s };
|