storybook-addon-vis 0.7.0 → 0.9.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.
Files changed (43) hide show
  1. package/dist/{chunk-LAWHEQMO.js → chunk-EYGWSOX2.js} +60 -26
  2. package/dist/chunk-EYGWSOX2.js.map +1 -0
  3. package/dist/chunk-FLRCYKBG.js +17 -0
  4. package/dist/chunk-FLRCYKBG.js.map +1 -0
  5. package/dist/index.d.ts +3 -3
  6. package/dist/index.js +2 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/preview-C2OcE4hp.d.ts +6 -0
  9. package/dist/preview.d.ts +2 -2
  10. package/dist/preview.js +3 -3
  11. package/dist/preview.js.map +1 -1
  12. package/dist/{context-BX71asjt.d.ts → types-CqNsMDsD.d.ts} +13 -1
  13. package/dist/vitest-setup.d.ts +21 -33
  14. package/dist/vitest-setup.js +62 -32
  15. package/dist/vitest-setup.js.map +1 -1
  16. package/package.json +2 -1
  17. package/readme.md +63 -78
  18. package/src/@vitest/browser/context.ts +3 -0
  19. package/src/@vitest/browser/page.has_image_snapshot.ts +1 -5
  20. package/src/@vitest/browser/page.image_snapshot.ts +3 -7
  21. package/src/expect.to_match_image_snapshot.spec.ts +15 -4
  22. package/src/expect.to_match_image_snapshot.stories.tsx +9 -9
  23. package/src/expect.to_match_image_snapshot.ts +20 -4
  24. package/src/index.ts +1 -0
  25. package/src/param.stories.tsx +2 -1
  26. package/src/per_story.stories.tsx +1 -1
  27. package/src/preview.ts +2 -2
  28. package/src/should_take_snapshot.ts +13 -0
  29. package/src/state.ts +31 -1
  30. package/src/storybook/preview.ts +12 -4
  31. package/src/types.ts +11 -0
  32. package/src/vis.spec.ts +13 -0
  33. package/src/vis.ts +65 -0
  34. package/src/vitest-setup.spec.ts +0 -16
  35. package/src/vitest-setup.ts +4 -54
  36. package/dist/chunk-GN5INPRD.js +0 -11
  37. package/dist/chunk-GN5INPRD.js.map +0 -1
  38. package/dist/chunk-LAWHEQMO.js.map +0 -1
  39. package/dist/chunk-V67IWJFT.js +0 -12
  40. package/dist/chunk-V67IWJFT.js.map +0 -1
  41. package/dist/preview-BsZVLryd.d.ts +0 -5
  42. package/src/tags.spec.ts +0 -32
  43. package/src/tags.ts +0 -11
@@ -1,17 +1,55 @@
1
- import { state } from './chunk-GN5INPRD.js';
2
1
  import { getByAltText, getByRole, getByTestId, getByText, getByTitle, getByPlaceholderText, getByLabelText } from '@storybook/test';
3
2
  import { join } from 'pathe';
3
+ import { getCurrentTest } from 'vitest/suite';
4
4
  import dedent from 'dedent';
5
5
  import pixelmatch from 'pixelmatch';
6
6
  import { required } from 'type-plus';
7
7
 
8
+ // src/@vitest/browser/context.ts
9
+
8
10
  // src/@vitest/browser/constants.ts
9
11
  var imageSnapshotSymbol = Symbol.for("storybook-addon-vis/imageSnapshot");
10
12
  var imageSnapshotStubSymbol = Symbol.for("storybook-addon-vis/imageSnapshotStub");
13
+
14
+ // src/@vitest/browser/image_snapshot.logic.ts
15
+ function isImageSnapshot(subject) {
16
+ return !!subject && subject.type === imageSnapshotSymbol;
17
+ }
18
+ function assertImageSnapshot(subject) {
19
+ if (!isImageSnapshot(subject)) {
20
+ throw new Error("Expected subject to be an image snapshot");
21
+ }
22
+ }
23
+ function toSnapshotId(taskName) {
24
+ return `${taskName.replace(/[^a-z0-9]/gi, "-").toLowerCase()}`;
25
+ }
26
+
27
+ // src/state.ts
28
+ var state = {
29
+ name: "",
30
+ testFilepath: "",
31
+ taskName: "",
32
+ snapshot: {},
33
+ getSnapshotFilePaths(options) {
34
+ const test = getCurrentTest();
35
+ state.taskName = test.name;
36
+ const id = state.id = toSnapshotId(state.taskName);
37
+ state.snapshot[state.testFilepath][id] = state.snapshot[state.testFilepath][id] ?? { index: 1 };
38
+ const index = state.snapshot[state.testFilepath][state.id].index;
39
+ const snapshotFilename = options?.customizeSnapshotId ? `${options.customizeSnapshotId(state.id, index)}.png` : `${state.id}-${index}.png`;
40
+ const baselinePath = join(state.baselineDir, snapshotFilename);
41
+ const resultPath = join(state.resultDir, snapshotFilename);
42
+ const diffPath = join(state.diffDir, snapshotFilename);
43
+ return { snapshotFilename, baselinePath, resultPath, diffPath };
44
+ },
45
+ incrementSnapshotIndex() {
46
+ state.snapshot[state.testFilepath][state.id].index++;
47
+ }
48
+ };
49
+
50
+ // src/@vitest/browser/page.has_image_snapshot.ts
11
51
  async function hasImageSnapshot(options) {
12
- const index = state.snapshot[state.testFilepath][state.id].index;
13
- const snapshotFilename = options?.customizeSnapshotId ? `${options.customizeSnapshotId(state.id, index)}.png` : `${state.id}-${index}.png`;
14
- const baselinePath = join(state.baselineDir, snapshotFilename);
52
+ const { baselinePath } = state.getSnapshotFilePaths(options);
15
53
  return commands.existFile(baselinePath);
16
54
  }
17
55
 
@@ -52,17 +90,14 @@ async function toDataURL(imageData) {
52
90
 
53
91
  // src/@vitest/browser/page.image_snapshot.ts
54
92
  async function imageSnapshot(options) {
55
- const index = state.snapshot[state.testFilepath][state.id].index++;
56
- const snapshotFilename = options?.customizeSnapshotId ? `${options.customizeSnapshotId(state.id, index)}.png` : `${state.id}-${index}.png`;
57
- const baselinePath = join(state.baselineDir, snapshotFilename);
58
- const resultPath = join(state.resultDir, snapshotFilename);
59
- const diffPath = join(state.diffDir, snapshotFilename);
93
+ const { snapshotFilename, baselinePath, resultPath, diffPath } = state.getSnapshotFilePaths(options);
60
94
  const screenshot = await this.screenshot({
61
95
  base64: true,
62
96
  path: resultPath,
63
97
  element: options?.element,
64
98
  timeout: options?.timeout ?? 3e3
65
99
  });
100
+ state.incrementSnapshotIndex();
66
101
  const image = await toImageData(screenshot.base64);
67
102
  return {
68
103
  type: imageSnapshotSymbol,
@@ -107,6 +142,9 @@ var page = new Proxy(
107
142
  if (prop === "imageSnapshot") {
108
143
  return { type: imageSnapshotStubSymbol };
109
144
  }
145
+ if (prop === "hasImageSnapshot") {
146
+ return false;
147
+ }
110
148
  console.info(`\`page.${prop.toString()}\` does not exist when running in browser`);
111
149
  };
112
150
  }
@@ -118,19 +156,6 @@ var server = new Proxy({}, {
118
156
  }
119
157
  });
120
158
 
121
- // src/@vitest/browser/image_snapshot.logic.ts
122
- function isImageSnapshot(subject) {
123
- return !!subject && subject.type === imageSnapshotSymbol;
124
- }
125
- function assertImageSnapshot(subject) {
126
- if (!isImageSnapshot(subject)) {
127
- throw new Error("Expected subject to be an image snapshot");
128
- }
129
- }
130
- function toSnapshotId(taskName) {
131
- return `${taskName.replace(/[^a-z0-9]/gi, "-").toLowerCase()}`;
132
- }
133
-
134
159
  // src/image_resizer.ts
135
160
  var createImageResizer = ({ width, height }) => (image) => {
136
161
  if (image.width === width && image.height === height) {
@@ -160,7 +185,15 @@ var createImageResizer = ({ width, height }) => (image) => {
160
185
 
161
186
  // src/expect.to_match_image_snapshot.ts
162
187
  async function toMatchImageSnapshot(actual, options) {
163
- const subject = await actual;
188
+ const promise = toMatchImageSnapshotInternal(actual, options);
189
+ const test = getCurrentTest();
190
+ if (!test) return promise;
191
+ test.promises ??= [];
192
+ test.promises.push(promise);
193
+ return promise;
194
+ }
195
+ async function toMatchImageSnapshotInternal(actual, options) {
196
+ let subject = await actual;
164
197
  if (subject?.type === imageSnapshotStubSymbol) {
165
198
  return success;
166
199
  }
@@ -179,6 +212,7 @@ async function toMatchImageSnapshot(actual, options) {
179
212
  message: () => `\`toMatchImageSnapshot()\` expects the subject to be an element, locator, or result of \`page.imageSnapshot()\`, but got: \`${subject}\``
180
213
  };
181
214
  }
215
+ subject = await page.imageSnapshot({ element: subject });
182
216
  }
183
217
  assertImageSnapshot(subject);
184
218
  const baseline = await tryReadSnapshot(subject.baselinePath);
@@ -258,6 +292,6 @@ function toThresholdUnit({ failureThresholdType, width, height }, pixelDiff) {
258
292
  }
259
293
  }
260
294
 
261
- export { cdp, commands, page, server, toMatchImageSnapshot, toSnapshotId };
262
- //# sourceMappingURL=chunk-LAWHEQMO.js.map
263
- //# sourceMappingURL=chunk-LAWHEQMO.js.map
295
+ export { cdp, commands, page, server, state, toMatchImageSnapshot };
296
+ //# sourceMappingURL=chunk-EYGWSOX2.js.map
297
+ //# sourceMappingURL=chunk-EYGWSOX2.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":["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"]}
@@ -0,0 +1,17 @@
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
@@ -0,0 +1 @@
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"]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { M as MatchImageSnapshotOptions } from './context-BX71asjt.js';
2
- export { C as CustomizeSnapshotIdOptions, d as ImageSnapshot, I as ImageSnapshotMatcher, b as ImageSnapshotOptions, c as cdp, a as commands, p as page, s as server, t as toMatchImageSnapshot } from './context-BX71asjt.js';
3
- export { v as visStorybookPreview } from './preview-BsZVLryd.js';
1
+ import { M as MatchImageSnapshotOptions } from './types-CqNsMDsD.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-CqNsMDsD.js';
3
+ export { d as defineVisPreview, s as storybookPreviewVis } from './preview-C2OcE4hp.js';
4
4
  import '@vitest/browser/context';
5
5
  import '@vitest/expect';
6
6
  import 'pixelmatch';
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
- export { visStorybookPreview } from './chunk-V67IWJFT.js';
2
- export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-LAWHEQMO.js';
3
- import './chunk-GN5INPRD.js';
1
+ export { defineVisPreview, storybookPreviewVis } from './chunk-FLRCYKBG.js';
2
+ export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-EYGWSOX2.js';
4
3
 
5
4
  // src/param.ts
6
5
  function defineSnapshotParam(snapshot) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/param.ts"],"names":[],"mappings":";;;;;AAEO,SAAS,oBAAoB,QAAqC,EAAA;AACxE,EAAA,OAAO,EAAE,QAAS,EAAA;AACnB","file":"index.js","sourcesContent":["import type { MatchImageSnapshotOptions } from './expect.to_match_image_snapshot'\n\nexport function defineSnapshotParam(snapshot: MatchImageSnapshotOptions) {\n\treturn { snapshot }\n}\n"]}
1
+ {"version":3,"sources":["../src/param.ts"],"names":[],"mappings":";;;;AAEO,SAAS,oBAAoB,QAAqC,EAAA;AACxE,EAAA,OAAO,EAAE,QAAS,EAAA;AACnB","file":"index.js","sourcesContent":["import type { MatchImageSnapshotOptions } from './expect.to_match_image_snapshot'\n\nexport function defineSnapshotParam(snapshot: MatchImageSnapshotOptions) {\n\treturn { snapshot }\n}\n"]}
@@ -0,0 +1,6 @@
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 };
package/dist/preview.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { v as visStorybookPreview } from './preview-BsZVLryd.js';
1
+ import { s as storybookPreviewVis } from './preview-C2OcE4hp.js';
2
2
  import 'storybook/internal/types';
3
3
 
4
4
 
5
5
 
6
- export { visStorybookPreview as default };
6
+ export { storybookPreviewVis as default };
package/dist/preview.js CHANGED
@@ -1,8 +1,8 @@
1
- import { visStorybookPreview } from './chunk-V67IWJFT.js';
2
- import './chunk-GN5INPRD.js';
1
+ import { storybookPreviewVis } from './chunk-FLRCYKBG.js';
2
+ import './chunk-EYGWSOX2.js';
3
3
 
4
4
  // src/preview.ts
5
- var preview_default = visStorybookPreview;
5
+ var preview_default = storybookPreviewVis;
6
6
 
7
7
  export { preview_default as default };
8
8
  //# sourceMappingURL=preview.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/preview.ts"],"names":[],"mappings":";;;;AAEA,IAAO,eAAQ,GAAA","file":"preview.js","sourcesContent":["import { visStorybookPreview } from './storybook/preview'\n\nexport default visStorybookPreview\n"]}
1
+ {"version":3,"sources":["../src/preview.ts"],"names":[],"mappings":";;;;AAEA,IAAO,eAAQ,GAAA","file":"preview.js","sourcesContent":["import { storybookPreviewVis } from './storybook/preview'\n\nexport default storybookPreviewVis\n"]}
@@ -129,4 +129,16 @@ declare const server: {
129
129
  config: SerializedConfig;
130
130
  };
131
131
 
132
- export { type CustomizeSnapshotIdOptions as C, type ImageSnapshotMatcher as I, type MatchImageSnapshotOptions as M, commands as a, type ImageSnapshotOptions as b, cdp as c, type ImageSnapshot as d, page as p, server as s, toMatchImageSnapshot as t };
132
+ /**
133
+ * The project parameters for the snapshot.
134
+ *
135
+ * These parameters are set per project in the `.storybook/preview.ts` file.
136
+ */
137
+ type VisOptions = {
138
+ /**
139
+ * The snapshot folder relative to the root of the project.
140
+ */
141
+ snapshotPath: string;
142
+ };
143
+
144
+ 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 };
@@ -1,9 +1,27 @@
1
- export { I as ImageSnapshotMatcher, M as MatchImageSnapshotOptions, c as cdp, a as commands, p as page, s as server, t as toMatchImageSnapshot } from './context-BX71asjt.js';
1
+ import { V as VisOptions } from './types-CqNsMDsD.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-CqNsMDsD.js';
2
3
  import '@vitest/browser/context';
3
4
  import '@vitest/expect';
4
5
  import 'pixelmatch';
5
6
  import 'vitest';
6
7
 
8
+ declare function createVisConfig(options?: VisOptions): {
9
+ presets: {
10
+ basic(): void;
11
+ theme(themes: Record<string, () => void | Promise<void>>): void;
12
+ };
13
+ beforeAll(suite: {
14
+ file: {
15
+ filepath: string;
16
+ };
17
+ name: string;
18
+ }): Promise<void>;
19
+ afterEach: {
20
+ matchImageSnapshot(): Promise<void>;
21
+ matchPerTheme(themes: Record<string, () => Promise<void> | void>): () => Promise<void>;
22
+ };
23
+ };
24
+
7
25
  /**
8
26
  * Determine should snapshot be taken.
9
27
  *
@@ -11,36 +29,6 @@ import 'vitest';
11
29
  * no `snapshot` tag: false
12
30
  * disabled by `!snapshot` tag: false
13
31
  */
14
- declare function shouldTakeSnapshot(ctx: {
15
- story?: {
16
- tags: string[];
17
- };
18
- }): boolean;
19
-
20
- /**
21
- * The project parameters for the snapshot.
22
- *
23
- * These parameters are set per project in the `.storybook/preview.ts` file.
24
- */
25
- type VisOptions = {
26
- /**
27
- * The snapshot folder relative to the root of the project.
28
- */
29
- snapshotPath: string;
30
- };
31
- declare function configureSnapshotBeforeAll(suite: {
32
- file: {
33
- filepath: string;
34
- };
35
- name: string;
36
- }, options?: VisOptions): Promise<void>;
37
- declare function configureSnapshotBeforeEach(ctx: {
38
- task: {
39
- name: string;
40
- file: {
41
- filepath: string;
42
- };
43
- };
44
- }): void;
32
+ declare function shouldTakeSnapshot(): boolean;
45
33
 
46
- export { type VisOptions, configureSnapshotBeforeAll, configureSnapshotBeforeEach, shouldTakeSnapshot };
34
+ export { createVisConfig, shouldTakeSnapshot };
@@ -1,40 +1,70 @@
1
- import { commands, toSnapshotId } from './chunk-LAWHEQMO.js';
2
- export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-LAWHEQMO.js';
3
- import { state } from './chunk-GN5INPRD.js';
1
+ import { state, toMatchImageSnapshot, commands, page } from './chunk-EYGWSOX2.js';
2
+ export { cdp, commands, page, server, toMatchImageSnapshot } from './chunk-EYGWSOX2.js';
4
3
  import { basename, join, dirname, relative } from 'pathe';
4
+ import { expect } from 'vitest';
5
5
 
6
- // src/tags.ts
7
- function shouldTakeSnapshot(ctx) {
8
- if (!ctx.story?.tags) return false;
9
- return ctx.story.tags.lastIndexOf("!snapshot") < ctx.story.tags.lastIndexOf("snapshot");
6
+ // src/should_take_snapshot.ts
7
+ function shouldTakeSnapshot() {
8
+ if (!state.tags) return false;
9
+ return state.tags.lastIndexOf("!snapshot") < state.tags.lastIndexOf("snapshot");
10
10
  }
11
11
 
12
- // src/vitest-setup.ts
13
- async function configureSnapshotBeforeAll(suite, options) {
14
- state.name = suite.name;
15
- state.testFilepath = suite.file.filepath;
16
- state.testFilename = basename(state.testFilepath);
17
- state.projectDir = state.testFilepath.slice(0, -state.name.length);
18
- const snapshotPath = join(
19
- state.projectDir,
20
- options?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`
21
- );
22
- const currentDir = dirname(state.testFilepath);
23
- state.baselineDir = relative(currentDir, join(snapshotPath, state.testFilename));
24
- state.resultDir = relative(currentDir, join(snapshotPath, "__results__", state.testFilename));
25
- state.diffDir = relative(currentDir, join(snapshotPath, "__diff_output__", state.testFilename));
26
- if (!state.snapshot[state.testFilepath]) {
27
- state.snapshot[state.testFilepath] = {};
28
- await commands.rmDir(state.resultDir);
29
- await commands.rmDir(state.diffDir);
30
- }
31
- }
32
- function configureSnapshotBeforeEach(ctx) {
33
- state.taskName = ctx.task.name;
34
- const id = state.id = toSnapshotId(state.taskName);
35
- state.snapshot[state.testFilepath][id] = state.snapshot[state.testFilepath][id] ?? { index: 1 };
12
+ // src/vis.ts
13
+ function createVisConfig(options) {
14
+ expect.extend({ toMatchImageSnapshot });
15
+ const h = {
16
+ presets: {
17
+ basic() {
18
+ beforeAll(h.beforeAll);
19
+ afterEach(h.afterEach.matchImageSnapshot);
20
+ },
21
+ theme(themes) {
22
+ beforeAll(h.beforeAll);
23
+ afterEach(h.afterEach.matchPerTheme(themes));
24
+ }
25
+ },
26
+ async beforeAll(suite) {
27
+ state.name = suite.name;
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
+ }
44
+ },
45
+ afterEach: {
46
+ async matchImageSnapshot() {
47
+ if (!shouldTakeSnapshot()) return;
48
+ const r = await page.imageSnapshot();
49
+ expect(r).toMatchImageSnapshot();
50
+ },
51
+ matchPerTheme(themes) {
52
+ return async function matchImageSnapshot() {
53
+ if (!shouldTakeSnapshot()) return;
54
+ for (const themeId in themes) {
55
+ await themes[themeId]();
56
+ const r = await page.imageSnapshot({
57
+ customizeSnapshotId: (id) => `${id}-${themeId}`
58
+ });
59
+ await expect(r).toMatchImageSnapshot();
60
+ }
61
+ };
62
+ }
63
+ }
64
+ };
65
+ return h;
36
66
  }
37
67
 
38
- export { configureSnapshotBeforeAll, configureSnapshotBeforeEach, shouldTakeSnapshot };
68
+ export { createVisConfig, shouldTakeSnapshot };
39
69
  //# sourceMappingURL=vitest-setup.js.map
40
70
  //# sourceMappingURL=vitest-setup.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tags.ts","../src/vitest-setup.ts"],"names":[],"mappings":";;;;;;AAOO,SAAS,mBAAmB,GAAqC,EAAA;AACvE,EAAA,IAAI,CAAC,GAAA,CAAI,KAAO,EAAA,IAAA,EAAa,OAAA,KAAA;AAC7B,EAAO,OAAA,GAAA,CAAI,KAAM,CAAA,IAAA,CAAK,WAAY,CAAA,WAAW,IAAI,GAAI,CAAA,KAAA,CAAM,IAAK,CAAA,WAAA,CAAY,UAAU,CAAA;AACvF;;;ACYA,eAAsB,0BAAA,CACrB,OACA,OACC,EAAA;AACD,EAAA,KAAA,CAAM,OAAO,KAAM,CAAA,IAAA;AACnB,EAAM,KAAA,CAAA,YAAA,GAAe,MAAM,IAAK,CAAA,QAAA;AAChC,EAAM,KAAA,CAAA,YAAA,GAAe,QAAS,CAAA,KAAA,CAAM,YAAY,CAAA;AAChD,EAAM,KAAA,CAAA,UAAA,GAAa,MAAM,YAAa,CAAA,KAAA,CAAM,GAAG,CAAC,KAAA,CAAM,KAAK,MAAM,CAAA;AACjE,EAAA,MAAM,YAAe,GAAA,IAAA;AAAA,IACpB,KAAM,CAAA,UAAA;AAAA,IACN,SAAS,YAAgB,IAAA,CAAA,cAAA,EAAiB,MAAM,QAAA,CAAS,qBAAqB,CAAA;AAAA,GAC/E;AACA,EAAM,MAAA,UAAA,GAAa,OAAQ,CAAA,KAAA,CAAM,YAAY,CAAA;AAC7C,EAAA,KAAA,CAAM,cAAc,QAAS,CAAA,UAAA,EAAY,KAAK,YAAc,EAAA,KAAA,CAAM,YAAY,CAAC,CAAA;AAC/E,EAAM,KAAA,CAAA,SAAA,GAAY,SAAS,UAAY,EAAA,IAAA,CAAK,cAAc,aAAe,EAAA,KAAA,CAAM,YAAY,CAAC,CAAA;AAC5F,EAAM,KAAA,CAAA,OAAA,GAAU,SAAS,UAAY,EAAA,IAAA,CAAK,cAAc,iBAAmB,EAAA,KAAA,CAAM,YAAY,CAAC,CAAA;AAE9F,EAAA,IAAI,CAAC,KAAA,CAAM,QAAS,CAAA,KAAA,CAAM,YAAY,CAAG,EAAA;AACxC,IAAA,KAAA,CAAM,QAAS,CAAA,KAAA,CAAM,YAAY,CAAA,GAAI,EAAC;AACtC,IAAM,MAAA,QAAA,CAAS,KAAM,CAAA,KAAA,CAAM,SAAS,CAAA;AACpC,IAAM,MAAA,QAAA,CAAS,KAAM,CAAA,KAAA,CAAM,OAAO,CAAA;AAAA;AAEpC;AAEO,SAAS,4BAA4B,GAOzC,EAAA;AACF,EAAM,KAAA,CAAA,QAAA,GAAW,IAAI,IAAK,CAAA,IAAA;AAC1B,EAAA,MAAM,EAAM,GAAA,KAAA,CAAM,EAAK,GAAA,YAAA,CAAa,MAAM,QAAQ,CAAA;AAClD,EAAA,KAAA,CAAM,QAAS,CAAA,KAAA,CAAM,YAAY,CAAA,CAAE,EAAE,CAAI,GAAA,KAAA,CAAM,QAAS,CAAA,KAAA,CAAM,YAAY,CAAE,CAAA,EAAE,CAAK,IAAA,EAAE,OAAO,CAAE,EAAA;AAC/F","file":"vitest-setup.js","sourcesContent":["/**\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(ctx: { story?: { tags: string[] } }) {\n\tif (!ctx.story?.tags) return false\n\treturn ctx.story.tags.lastIndexOf('!snapshot') < ctx.story.tags.lastIndexOf('snapshot')\n}\n","import { basename, dirname, join, relative } from 'pathe'\nimport './augment.js'\nimport { commands } from './@vitest/browser/context.js'\nimport { toSnapshotId } from './@vitest/browser/image_snapshot.logic.js'\nimport { state } from './state.js'\n\nexport * from './@vitest/browser/context.js'\nexport * from './expect.to_match_image_snapshot.js'\nexport * from './tags.js'\n\n/**\n * The project parameters for the snapshot.\n *\n * These parameters are set per project in the `.storybook/preview.ts` file.\n */\nexport type VisOptions = {\n\t/**\n\t * The snapshot folder relative to the root of the project.\n\t */\n\tsnapshotPath: string\n}\n\nexport async function configureSnapshotBeforeAll(\n\tsuite: { file: { filepath: string }; name: string },\n\toptions?: VisOptions,\n) {\n\tstate.name = suite.name\n\tstate.testFilepath = suite.file.filepath\n\tstate.testFilename = basename(state.testFilepath)\n\tstate.projectDir = state.testFilepath.slice(0, -state.name.length)\n\tconst snapshotPath = join(\n\t\tstate.projectDir,\n\t\toptions?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`,\n\t)\n\tconst currentDir = dirname(state.testFilepath)\n\tstate.baselineDir = relative(currentDir, join(snapshotPath, state.testFilename))\n\tstate.resultDir = relative(currentDir, join(snapshotPath, '__results__', state.testFilename))\n\tstate.diffDir = relative(currentDir, join(snapshotPath, '__diff_output__', state.testFilename))\n\n\tif (!state.snapshot[state.testFilepath]) {\n\t\tstate.snapshot[state.testFilepath] = {}\n\t\tawait commands.rmDir(state.resultDir)\n\t\tawait commands.rmDir(state.diffDir)\n\t}\n}\n\nexport function configureSnapshotBeforeEach(ctx: {\n\ttask: {\n\t\tname: string\n\t\tfile: {\n\t\t\tfilepath: string\n\t\t}\n\t}\n}) {\n\tstate.taskName = ctx.task.name\n\tconst id = (state.id = toSnapshotId(state.taskName))\n\tstate.snapshot[state.testFilepath][id] = state.snapshot[state.testFilepath][id] ?? { index: 1 }\n}\n"]}
1
+ {"version":3,"sources":["../src/should_take_snapshot.ts","../src/vis.ts"],"names":[],"mappings":"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","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\tif (!state.tags) return false\n\treturn state.tags.lastIndexOf('!snapshot') < state.tags.lastIndexOf('snapshot')\n}\n","import { basename, dirname, join, relative } from 'pathe'\nimport { expect } from 'vitest'\nimport { commands, 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\nexport function createVisConfig(options?: VisOptions) {\n\texpect.extend({ toMatchImageSnapshot })\n\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\tstate.name = suite.name\n\t\t\tstate.testFilepath = suite.file.filepath\n\t\t\tstate.testFilename = basename(state.testFilepath)\n\t\t\tstate.projectDir = state.testFilepath.slice(0, -state.name.length)\n\t\t\tconst snapshotPath = join(\n\t\t\t\tstate.projectDir,\n\t\t\t\toptions?.snapshotPath ?? `__snapshots__/${await commands.getSnapshotPlatform()}`,\n\t\t\t)\n\t\t\tconst currentDir = dirname(state.testFilepath)\n\t\t\tstate.baselineDir = relative(currentDir, join(snapshotPath, state.testFilename))\n\t\t\tstate.resultDir = relative(currentDir, join(snapshotPath, '__results__', state.testFilename))\n\t\t\tstate.diffDir = relative(currentDir, join(snapshotPath, '__diff_output__', state.testFilename))\n\n\t\t\tif (!state.snapshot[state.testFilepath]) {\n\t\t\t\tstate.snapshot[state.testFilepath] = {}\n\t\t\t\tawait commands.rmDir(state.resultDir)\n\t\t\t\tawait commands.rmDir(state.diffDir)\n\t\t\t}\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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-vis",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Storybook Vitest Image Snapshot addon",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -57,6 +57,7 @@
57
57
  "@storybook/react": "^8.4.2",
58
58
  "@storybook/react-vite": "^8.4.2",
59
59
  "@storybook/test": "^8.4.2",
60
+ "@testing-library/react": "^16.0.1",
60
61
  "@types/is-ci": "^3.0.4",
61
62
  "@types/pixelmatch": "^5.2.6",
62
63
  "@types/react": "^18.2.65",