storybook-addon-vis 0.0.11 → 0.0.12

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/index.d.ts CHANGED
@@ -29,6 +29,7 @@ declare module '@vitest/browser/context' {
29
29
  interface BrowserCommands {
30
30
  existDir: (path: string) => Promise<boolean>;
31
31
  copyFile: (src: string, dest: string) => Promise<void>;
32
+ rmDir: (path: string) => Promise<void>;
32
33
  }
33
34
  }
34
35
  declare global {
@@ -74,36 +75,6 @@ declare const server: {
74
75
  config: SerializedConfig;
75
76
  };
76
77
 
77
- /**
78
- * The project parameters for the snapshot.
79
- *
80
- * These parameters are set per project in the `.storybook/preview.ts` file.
81
- */
82
- type SnapshotProjectParam = {
83
- /**
84
- * The snapshot folder relative to the root of the project.
85
- */
86
- snapshotPath: string;
87
- /**
88
- * The baseline folder under the snapshot folder specified in `snapshotPath`.
89
- */
90
- baseline: string;
91
- /**
92
- * The result folder under the snapshot folder specified in `snapshotPath`.
93
- *
94
- * This folder stores the snapshot of the current test run.
95
- */
96
- result: string;
97
- /**
98
- * The diff folder under the snapshot folder specified in `snapshotPath`.
99
- *
100
- * This folder stores the diff of the current test run if the test fails.
101
- */
102
- diff: string;
103
- };
104
- declare function defineSnapshotProjectParam(snapshot: Partial<SnapshotProjectParam>): {
105
- snapshot: Partial<SnapshotProjectParam>;
106
- };
107
78
  type SnapshotStoryParam = {
108
79
  /**
109
80
  * Add a delay to the story snapshot comparison to allow for async rendering.
@@ -131,4 +102,4 @@ declare function defineSnapshotParam(snapshot: SnapshotStoryParam): {
131
102
  snapshot: SnapshotStoryParam;
132
103
  };
133
104
 
134
- export { type ImageSnapshot, type ImageSnapshotOptions, type MatchImageSnapshotOptions, type SnapshotProjectParam, type SnapshotStoryParam, cdp, commands, defineSnapshotParam, defineSnapshotProjectParam, page, server, toMatchImageSnapshot };
105
+ export { type ImageSnapshot, type ImageSnapshotOptions, type MatchImageSnapshotOptions, type SnapshotStoryParam, cdp, commands, defineSnapshotParam, page, server, toMatchImageSnapshot };
package/dist/index.js CHANGED
@@ -2,5 +2,5 @@ import F from'dedent';import M from'pixelmatch';import {getByAltText,getByRole,g
2
2
 
3
3
  Expected: '${a.baselinePath}'
4
4
  Actual: '${a.resultPath}'
5
- Difference: '${a.diffPath}'`})}var b={pass:!0,message:()=>""};function R(t){return l.readFile(t,{encoding:"base64"}).catch(()=>{})}async function z(t,e){let a=(await x(e)).split(",")[1];return l.writeFile(t,a,"base64url")}function A(t,e){if(O(t,e))return [t,e];let a=k(t,e),n=L(a);return [n(t),n(e)]}function k(t,e){let a=Math.max(t.width,e.width),n=Math.max(t.height,e.height);return {width:a,height:n}}function O(t,e){return t.width===e.width&&t.height===e.height}var L=({width:t,height:e})=>a=>{if(a.width===t&&a.height===e)return a;let n=(r,s)=>s<=a.height&&r<=a.width,o=new ImageData(t,e,{colorSpace:a.colorSpace});for(let r=0;r<e;r++)for(let s=0;s<t;s++){let i=t*r+s<<2;if(n(s,r)){let m=a.width*r+s<<2;o.data[i]=a.data[m],o.data[i+1]=a.data[m+1],o.data[i+2]=a.data[m+2],o.data[i+3]=a.data[m+3];}else o.data[i]=0,o.data[i+1]=0,o.data[i+2]=0,o.data[i+3]=64;}return o};function _(t,e,{failureThreshold:a=0,failureThresholdType:n="pixel",diffOptions:o}={}){let{width:r,height:s}=e,i=new ImageData(r,s),m=M(e.data,t.data,i.data,r,s,o),c=N({failureThresholdType:n,width:r,height:s},m);return {pass:c<=a,diffAmount:c,diffImage:i}}function N({failureThresholdType:t,width:e,height:a},n){switch(t){case"pixel":return n;case"percent":return n/(e*a)*100;default:throw new Error(`Invalid failureThresholdType: ${t}`)}}function dt(t){return {snapshot:t}}function ft(t){return {snapshot:t}}export{at as cdp,l as commands,ft as defineSnapshotParam,dt as defineSnapshotProjectParam,C as page,nt as server,ct as toMatchImageSnapshot};//# sourceMappingURL=index.js.map
5
+ Difference: '${a.diffPath}'`})}var b={pass:!0,message:()=>""};function R(t){return l.readFile(t,{encoding:"base64"}).catch(()=>{})}async function z(t,e){let a=(await x(e)).split(",")[1];return l.writeFile(t,a,"base64url")}function A(t,e){if(O(t,e))return [t,e];let a=k(t,e),n=L(a);return [n(t),n(e)]}function k(t,e){let a=Math.max(t.width,e.width),n=Math.max(t.height,e.height);return {width:a,height:n}}function O(t,e){return t.width===e.width&&t.height===e.height}var L=({width:t,height:e})=>a=>{if(a.width===t&&a.height===e)return a;let n=(r,s)=>s<=a.height&&r<=a.width,o=new ImageData(t,e,{colorSpace:a.colorSpace});for(let r=0;r<e;r++)for(let s=0;s<t;s++){let i=t*r+s<<2;if(n(s,r)){let m=a.width*r+s<<2;o.data[i]=a.data[m],o.data[i+1]=a.data[m+1],o.data[i+2]=a.data[m+2],o.data[i+3]=a.data[m+3];}else o.data[i]=0,o.data[i+1]=0,o.data[i+2]=0,o.data[i+3]=64;}return o};function _(t,e,{failureThreshold:a=0,failureThresholdType:n="pixel",diffOptions:o}={}){let{width:r,height:s}=e,i=new ImageData(r,s),m=M(e.data,t.data,i.data,r,s,o),c=N({failureThresholdType:n,width:r,height:s},m);return {pass:c<=a,diffAmount:c,diffImage:i}}function N({failureThresholdType:t,width:e,height:a},n){switch(t){case"pixel":return n;case"percent":return n/(e*a)*100;default:throw new Error(`Invalid failureThresholdType: ${t}`)}}function dt(t){return {snapshot:t}}export{at as cdp,l as commands,dt as defineSnapshotParam,C as page,nt as server,ct as toMatchImageSnapshot};//# sourceMappingURL=index.js.map
6
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/@vitest/browser/constants.ts","../src/image_data.ts","../src/state.ts","../src/@vitest/browser/image_snapshot.logic.ts","../src/@vitest/browser/page.image_snapshot.ts","../src/@vitest/browser/context.ts","../src/expect.to_match_image_snapshot.ts","../src/param.ts"],"names":["imageSnapshotSymbol","imageSnapshotStubSymbol","toImageData","base64","resolve","reject","img","canvas","ctx","toDataURL","imageData","blob","reader","state","isImageSnapshot","subject","assertImageSnapshot","toSnapshotId","taskName","imageSnapshot","options","testfilename","basename","snapshotFilename","baselinePath","join","resultPath","diffPath","screenshot","image","m","page","cdp","commands","target","prop","getByAltText","getByRole","getByTestId","getByText","getByTitle","getByPlaceholderText","getByLabelText","server","toMatchImageSnapshot","actual","success","baseline","tryReadSnapshot","originalImage","resultImage","baselineImage","alignImagesToSameSize","pass","diffAmount","diffImage","compareImage","writeSnapshot","dedent","path","content","image1","image2","isSameSize","size","getMaxSize","resize","createImageResizer","width","height","inArea","x","y","result","idx","old","failureThreshold","failureThresholdType","diffOptions","pixelDiff","pixelmatch","toThresholdUnit","defineSnapshotProjectParam","snapshot","defineSnapshotParam"],"mappings":"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","file":"index.js","sourcesContent":["export const imageSnapshotSymbol = Symbol.for('storybook-addon-vis/imageSnapshot')\n\nexport const imageSnapshotStubSymbol = Symbol.for('storybook-addon-vis/imageSnapshotStub')\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","export const state = {\n\tname: '',\n\ttestFilepath: '',\n\ttaskName: '',\n\tsnapshot: {},\n} as {\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\tsnapshot: Record<string, { index: number }>\n}\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 type { BrowserPage } from '@vitest/browser/context'\nimport { basename, join } from 'pathe'\nimport { toImageData } from '../../image_data.js'\nimport { state } from '../../state.js'\nimport { imageSnapshotSymbol } from './constants.js'\nimport { toSnapshotId } from './image_snapshot.logic.js'\nimport type { ImageSnapshot, ImageSnapshotOptions } from './types.js'\n\nexport async function imageSnapshot(this: BrowserPage, options?: ImageSnapshotOptions): Promise<ImageSnapshot> {\n\t// const rootDir = server.config.root\n\tconst testfilename = basename(state.testFilepath)\n\tconst snapshotFilename = `${toSnapshotId(state.taskName)}-${state.snapshot[state.taskName]!.index++}.png`\n\tconst baselinePath = join(state.baselineDir, testfilename, snapshotFilename)\n\tconst resultPath = join(state.resultDir, testfilename, snapshotFilename)\n\tconst diffPath = join(state.diffDir, testfilename, snapshotFilename)\n\tconst screenshot = await this.screenshot({\n\t\tbase64: true,\n\t\tpath: resultPath,\n\t\telement: options?.element,\n\t})\n\tconst image = await toImageData(screenshot.base64)\n\n\treturn {\n\t\ttype: imageSnapshotSymbol,\n\t\t// rootDir,\n\t\ttestfilename,\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 { 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 })\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() ?? {}\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\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","import type { AsyncExpectationResult } from '@vitest/expect'\nimport dedent from 'dedent'\nimport pixelmatch from 'pixelmatch'\nimport { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'\nimport { commands } from './@vitest/browser/context.js'\nimport { assertImageSnapshot, isImageSnapshot } from './@vitest/browser/image_snapshot.logic.js'\nimport type { MatchImageSnapshotOptions } from './@vitest/browser/types.js'\nimport { toDataURL, toImageData } from './image_data.js'\n\nexport async function toMatchImageSnapshot(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tconst 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,\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,\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: \\`${actual}\\``,\n\t\t\t}\n\t\t}\n\t\t// subject = await page.imageSnapshot({ element: actual })\n\t}\n\tassertImageSnapshot(subject)\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\tconst { pass, diffAmount, diffImage } = compareImage(baselineImage, resultImage, options)\n\tif (!pass) {\n\t\tawait writeSnapshot(`${subject.diffPath}`, diffImage)\n\t\treturn {\n\t\t\tpass: false,\n\t\t\tactual,\n\t\t\tmessage: () =>\n\t\t\t\tdedent`${\n\t\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\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\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\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\nconst 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\t\treturn result\n\t}\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","import type { PixelmatchOptions } from 'pixelmatch'\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 SnapshotProjectParam = {\n\t/**\n\t * The snapshot folder relative to the root of the project.\n\t */\n\tsnapshotPath: string\n\t/**\n\t * The baseline folder under the snapshot folder specified in `snapshotPath`.\n\t */\n\tbaseline: string\n\t/**\n\t * The result folder under the snapshot folder specified in `snapshotPath`.\n\t *\n\t * This folder stores the snapshot of the current test run.\n\t */\n\tresult: string\n\t/**\n\t * The diff folder under the snapshot folder specified in `snapshotPath`.\n\t *\n\t * This folder stores the diff of the current test run if the test fails.\n\t */\n\tdiff: string\n}\n\nexport function defineSnapshotProjectParam(snapshot: Partial<SnapshotProjectParam>) {\n\treturn { snapshot }\n}\n\nexport type SnapshotStoryParam = {\n\t/**\n\t * Add a delay to the story snapshot comparison to allow for async rendering.\n\t *\n\t * This only apply to the automatic snapshot taken when the story is rendered.\n\t * In general, it's a good idea to not rely on this delay,\n\t * and instead use the make sure your component is fully rendered before the `play()` function returns.\n\t */\n\tdelay?: number | undefined\n\t/**\n\t * The method by which images are compared.\n\t * `pixelmatch` does a pixel by pixel comparison, whereas `ssim` does a structural similarity comparison.\n\t * @default 'pixelmatch'\n\t */\n\tcomparisonMethod?: 'pixelmatch' | 'ssim' | undefined\n\t/**\n\t * Custom config passed to 'pixelmatch' or 'ssim'\n\t */\n\tcustomDiffConfig?: PixelmatchOptions | undefined\n\tfailureThreshold?: number | undefined\n\tfailureThresholdType?: 'percent' | 'pixel' | undefined\n\tblur?: number | undefined\n}\n\nexport function defineSnapshotParam(snapshot: SnapshotStoryParam) {\n\treturn { snapshot }\n}\n"]}
1
+ {"version":3,"sources":["../src/@vitest/browser/constants.ts","../src/image_data.ts","../src/state.ts","../src/@vitest/browser/image_snapshot.logic.ts","../src/@vitest/browser/page.image_snapshot.ts","../src/@vitest/browser/context.ts","../src/expect.to_match_image_snapshot.ts","../src/param.ts"],"names":["imageSnapshotSymbol","imageSnapshotStubSymbol","toImageData","base64","resolve","reject","img","canvas","ctx","toDataURL","imageData","blob","reader","state","isImageSnapshot","subject","assertImageSnapshot","toSnapshotId","taskName","imageSnapshot","options","testfilename","basename","snapshotFilename","baselinePath","join","resultPath","diffPath","screenshot","image","m","page","cdp","commands","target","prop","getByAltText","getByRole","getByTestId","getByText","getByTitle","getByPlaceholderText","getByLabelText","server","toMatchImageSnapshot","actual","success","baseline","tryReadSnapshot","originalImage","resultImage","baselineImage","alignImagesToSameSize","pass","diffAmount","diffImage","compareImage","writeSnapshot","dedent","path","content","image1","image2","isSameSize","size","getMaxSize","resize","createImageResizer","width","height","inArea","x","y","result","idx","old","failureThreshold","failureThresholdType","diffOptions","pixelDiff","pixelmatch","toThresholdUnit","defineSnapshotParam","snapshot"],"mappings":"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","file":"index.js","sourcesContent":["export const imageSnapshotSymbol = Symbol.for('storybook-addon-vis/imageSnapshot')\n\nexport const imageSnapshotStubSymbol = Symbol.for('storybook-addon-vis/imageSnapshotStub')\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","export const state = {\n\tname: '',\n\ttestFilepath: '',\n\ttaskName: '',\n\tsnapshot: {},\n} as {\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\tsnapshot: Record<string, { index: number }>\n}\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 type { BrowserPage } from '@vitest/browser/context'\nimport { basename, join } from 'pathe'\nimport { toImageData } from '../../image_data.js'\nimport { state } from '../../state.js'\nimport { imageSnapshotSymbol } from './constants.js'\nimport { toSnapshotId } from './image_snapshot.logic.js'\nimport type { ImageSnapshot, ImageSnapshotOptions } from './types.js'\n\nexport async function imageSnapshot(this: BrowserPage, options?: ImageSnapshotOptions): Promise<ImageSnapshot> {\n\t// const rootDir = server.config.root\n\tconst testfilename = basename(state.testFilepath)\n\tconst snapshotFilename = `${toSnapshotId(state.taskName)}-${state.snapshot[state.taskName]!.index++}.png`\n\tconst baselinePath = join(state.baselineDir, testfilename, snapshotFilename)\n\tconst resultPath = join(state.resultDir, testfilename, snapshotFilename)\n\tconst diffPath = join(state.diffDir, testfilename, snapshotFilename)\n\tconst screenshot = await this.screenshot({\n\t\tbase64: true,\n\t\tpath: resultPath,\n\t\telement: options?.element,\n\t})\n\tconst image = await toImageData(screenshot.base64)\n\n\treturn {\n\t\ttype: imageSnapshotSymbol,\n\t\t// rootDir,\n\t\ttestfilename,\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 { 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 })\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() ?? {}\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\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","import type { AsyncExpectationResult } from '@vitest/expect'\nimport dedent from 'dedent'\nimport pixelmatch from 'pixelmatch'\nimport { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'\nimport { commands } from './@vitest/browser/context.js'\nimport { assertImageSnapshot, isImageSnapshot } from './@vitest/browser/image_snapshot.logic.js'\nimport type { MatchImageSnapshotOptions } from './@vitest/browser/types.js'\nimport { toDataURL, toImageData } from './image_data.js'\n\nexport async function toMatchImageSnapshot(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tconst 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,\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,\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: \\`${actual}\\``,\n\t\t\t}\n\t\t}\n\t\t// subject = await page.imageSnapshot({ element: actual })\n\t}\n\tassertImageSnapshot(subject)\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\tconst { pass, diffAmount, diffImage } = compareImage(baselineImage, resultImage, options)\n\tif (!pass) {\n\t\tawait writeSnapshot(`${subject.diffPath}`, diffImage)\n\t\treturn {\n\t\t\tpass: false,\n\t\t\tactual,\n\t\t\tmessage: () =>\n\t\t\t\tdedent`${\n\t\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\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\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\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\nconst 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\t\treturn result\n\t}\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","import type { PixelmatchOptions } from 'pixelmatch'\n\nexport type SnapshotStoryParam = {\n\t/**\n\t * Add a delay to the story snapshot comparison to allow for async rendering.\n\t *\n\t * This only apply to the automatic snapshot taken when the story is rendered.\n\t * In general, it's a good idea to not rely on this delay,\n\t * and instead use the make sure your component is fully rendered before the `play()` function returns.\n\t */\n\tdelay?: number | undefined\n\t/**\n\t * The method by which images are compared.\n\t * `pixelmatch` does a pixel by pixel comparison, whereas `ssim` does a structural similarity comparison.\n\t * @default 'pixelmatch'\n\t */\n\tcomparisonMethod?: 'pixelmatch' | 'ssim' | undefined\n\t/**\n\t * Custom config passed to 'pixelmatch' or 'ssim'\n\t */\n\tcustomDiffConfig?: PixelmatchOptions | undefined\n\tfailureThreshold?: number | undefined\n\tfailureThresholdType?: 'percent' | 'pixel' | undefined\n\tblur?: number | undefined\n}\n\nexport function defineSnapshotParam(snapshot: SnapshotStoryParam) {\n\treturn { snapshot }\n}\n"]}
@@ -27,6 +27,7 @@ declare module '@vitest/browser/context' {
27
27
  interface BrowserCommands {
28
28
  existDir: (path: string) => Promise<boolean>;
29
29
  copyFile: (src: string, dest: string) => Promise<void>;
30
+ rmDir: (path: string) => Promise<void>;
30
31
  }
31
32
  }
32
33
  declare global {
@@ -1,2 +1,2 @@
1
- import {copyFile,stat}from'node:fs/promises';import {mkdirp}from'mkdirp';import {join,dirname}from'pathe';var s=async({testPath:o,provider:r},t,i)=>{if(r.name==="playwright"){let n=join(dirname(o),i),a=dirname(n);return await mkdirp(a),copyFile(join(dirname(o),t),n)}throw new Error(`provider ${r.name} is not supported`)};var p=async({testPath:o,provider:r},t)=>{if(r.name==="playwright")return stat(join(dirname(o),t)).then(i=>i.isDirectory()).catch(()=>!1);throw new Error(`provider ${r.name} is not supported`)};function D(){return {name:"vitest:storybook-vis",config(){return {test:{browser:{name:void 0,commands:{existDir:p,copyFile:s}}}}}}}export{D as storybookVis};//# sourceMappingURL=vitest-plugin.js.map
1
+ import {copyFile,stat}from'node:fs/promises';import {mkdirp}from'mkdirp';import {join,dirname}from'pathe';import {rimraf}from'rimraf';var s=async({testPath:o,provider:r},t,i)=>{if(r.name==="playwright"){let m=join(dirname(o),i),f=dirname(m);return await mkdirp(f),copyFile(join(dirname(o),t),m)}throw new Error(`provider ${r.name} is not supported`)};var p=async({testPath:o,provider:r},t)=>{if(r.name==="playwright")return stat(join(dirname(o),t)).then(i=>i.isDirectory()).catch(()=>!1);throw new Error(`provider ${r.name} is not supported`)};var a=async({testPath:o,provider:r},t)=>{if(r.name==="playwright")return rimraf(join(dirname(o),t));throw new Error(`provider ${r.name} is not supported`)};function q(){return {name:"vitest:storybook-vis",config(){return {test:{browser:{name:void 0,commands:{existDir:p,copyFile:s,rmDir:a}}}}}}}export{q as storybookVis};//# sourceMappingURL=vitest-plugin.js.map
2
2
  //# sourceMappingURL=vitest-plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vitest-plugin/commands/copy_file.ts","../src/vitest-plugin/commands/exist_dir.ts","../src/vitest-plugin.ts"],"names":["copyFile","testPath","provider","src","dest","destPath","join","dirname","destDir","mkdirp","copyFileFs","existDir","path","stat","s","storybookVis"],"mappings":"0GAKO,IAAMA,CAAwD,CAAA,MAAO,CAAE,QAAA,CAAAC,CAAU,CAAA,QAAA,CAAAC,CAAS,CAAA,CAAGC,EAAKC,CAAS,GAAA,CACjH,GAAIF,CAAAA,CAAS,OAAS,YAAc,CAAA,CACnC,IAAMG,CAAAA,CAAWC,KAAKC,OAAQN,CAAAA,CAAQ,CAAGG,CAAAA,CAAI,CACvCI,CAAAA,CAAAA,CAAUD,OAAQF,CAAAA,CAAQ,EAChC,OAAMI,MAAAA,MAAAA,CAAOD,CAAO,CAAA,CACbE,SAAWJ,IAAKC,CAAAA,OAAAA,CAAQN,CAAQ,CAAA,CAAGE,CAAG,CAAGE,CAAAA,CAAQ,CACzD,CAEA,MAAM,IAAI,KAAM,CAAA,CAAA,SAAA,EAAYH,EAAS,IAAI,CAAA,iBAAA,CAAmB,CAC7D,CAAA,CCVO,IAAMS,CAAAA,CAA2C,MAAO,CAAE,SAAAV,CAAU,CAAA,QAAA,CAAAC,CAAS,CAAA,CAAGU,CAAS,GAAA,CAC/F,GAAIV,CAAAA,CAAS,OAAS,YACrB,CAAA,OAAOW,IAAKP,CAAAA,IAAAA,CAAKC,OAAQN,CAAAA,CAAQ,CAAGW,CAAAA,CAAI,CAAC,CACvC,CAAA,IAAA,CAAME,CAAMA,EAAAA,CAAAA,CAAE,aAAa,CAAA,CAC3B,KAAM,CAAA,IAAM,EAAK,CAGpB,CAAA,MAAM,IAAI,KAAA,CAAM,CAAYZ,SAAAA,EAAAA,CAAAA,CAAS,IAAI,CAAA,iBAAA,CAAmB,CAC7D,CCPO,CAAA,SAASa,CAAuB,EAAA,CACtC,OAAO,CACN,IAAA,CAAM,sBACN,CAAA,MAAA,EAAS,CACR,OAAO,CACN,IAAM,CAAA,CACL,OAAS,CAAA,CACR,IAAM,CAAA,KAAA,CAAA,CACN,SAAU,CACT,QAAA,CAAAJ,CACA,CAAA,QAAA,CAAAX,CACD,CACD,CACD,CACD,CACD,CACD,CACD","file":"vitest-plugin.js","sourcesContent":["import { copyFile as copyFileFs } from 'node:fs/promises'\nimport { mkdirp } from 'mkdirp'\nimport { dirname, join } from 'pathe'\nimport type { BrowserCommand } from 'vitest/node'\n\nexport const copyFile: BrowserCommand<[src: string, dest: string]> = async ({ testPath, provider }, src, dest) => {\n\tif (provider.name === 'playwright') {\n\t\tconst destPath = join(dirname(testPath), dest)\n\t\tconst destDir = dirname(destPath)\n\t\tawait mkdirp(destDir)\n\t\treturn copyFileFs(join(dirname(testPath), src), destPath)\n\t}\n\n\tthrow new Error(`provider ${provider.name} is not supported`)\n}\n","import { stat } from 'node:fs/promises'\nimport { dirname, join } from 'pathe'\nimport type { BrowserCommand } from 'vitest/node'\n\nexport const existDir: BrowserCommand<[path: string]> = async ({ testPath, provider }, path) => {\n\tif (provider.name === 'playwright') {\n\t\treturn stat(join(dirname(testPath), path))\n\t\t\t.then((s) => s.isDirectory())\n\t\t\t.catch(() => false)\n\t}\n\n\tthrow new Error(`provider ${provider.name} is not supported`)\n}\n","import type { Plugin } from 'vitest/config'\nimport './augment.js'\nimport { copyFile } from './vitest-plugin/commands/copy_file.js'\nimport { existDir } from './vitest-plugin/commands/exist_dir.js'\n\nexport function storybookVis(): Plugin {\n\treturn {\n\t\tname: 'vitest:storybook-vis',\n\t\tconfig() {\n\t\t\treturn {\n\t\t\t\ttest: {\n\t\t\t\t\tbrowser: {\n\t\t\t\t\t\tname: undefined,\n\t\t\t\t\t\tcommands: {\n\t\t\t\t\t\t\texistDir,\n\t\t\t\t\t\t\tcopyFile,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t}\n}\n"]}
1
+ {"version":3,"sources":["../src/vitest-plugin/commands/copy_file.ts","../src/vitest-plugin/commands/exist_dir.ts","../src/vitest-plugin/commands/rm_dir.ts","../src/vitest-plugin.ts"],"names":["copyFile","testPath","provider","src","dest","destPath","join","dirname","destDir","mkdirp","copyFileFs","existDir","path","stat","s","rmDir","rimraf","storybookVis"],"mappings":"sIAKO,IAAMA,CAAwD,CAAA,MAAO,CAAE,QAAAC,CAAAA,CAAAA,CAAU,SAAAC,CAAS,CAAA,CAAGC,EAAKC,CAAS,GAAA,CACjH,GAAIF,CAAS,CAAA,IAAA,GAAS,aAAc,CACnC,IAAMG,EAAWC,IAAKC,CAAAA,OAAAA,CAAQN,CAAQ,CAAGG,CAAAA,CAAI,EACvCI,CAAUD,CAAAA,OAAAA,CAAQF,CAAQ,CAChC,CAAA,OAAA,MAAMI,OAAOD,CAAO,CAAA,CACbE,SAAWJ,IAAKC,CAAAA,OAAAA,CAAQN,CAAQ,CAAGE,CAAAA,CAAG,EAAGE,CAAQ,CACzD,CAEA,MAAM,IAAI,MAAM,CAAYH,SAAAA,EAAAA,CAAAA,CAAS,IAAI,CAAmB,iBAAA,CAAA,CAC7D,ECVO,IAAMS,EAA2C,MAAO,CAAE,SAAAV,CAAU,CAAA,QAAA,CAAAC,CAAS,CAAGU,CAAAA,CAAAA,GAAS,CAC/F,GAAIV,CAAAA,CAAS,OAAS,YACrB,CAAA,OAAOW,IAAKP,CAAAA,IAAAA,CAAKC,OAAQN,CAAAA,CAAQ,EAAGW,CAAI,CAAC,EACvC,IAAME,CAAAA,CAAAA,EAAMA,EAAE,WAAY,EAAC,EAC3B,KAAM,CAAA,IAAM,EAAK,CAGpB,CAAA,MAAM,IAAI,KAAM,CAAA,CAAA,SAAA,EAAYZ,EAAS,IAAI,CAAA,iBAAA,CAAmB,CAC7D,CCZA,CAIO,IAAMa,CAAwC,CAAA,MAAO,CAAE,QAAAd,CAAAA,CAAAA,CAAU,SAAAC,CAAS,CAAA,CAAGU,IAAS,CAC5F,GAAIV,CAAS,CAAA,IAAA,GAAS,YACrB,CAAA,OAAOc,OAAOV,IAAKC,CAAAA,OAAAA,CAAQN,CAAQ,CAAGW,CAAAA,CAAI,CAAC,CAG5C,CAAA,MAAM,IAAI,KAAM,CAAA,CAAA,SAAA,EAAYV,EAAS,IAAI,CAAA,iBAAA,CAAmB,CAC7D,CCJO,CAAA,SAASe,GAAuB,CACtC,OAAO,CACN,IAAM,CAAA,sBAAA,CACN,QAAS,CACR,OAAO,CACN,IAAM,CAAA,CACL,QAAS,CACR,IAAA,CAAM,OACN,QAAU,CAAA,CACT,SAAAN,CACA,CAAA,QAAA,CAAAX,EACA,KAAAe,CAAAA,CACD,CACD,CACD,CACD,CACD,CACD,CACD","file":"vitest-plugin.js","sourcesContent":["import { copyFile as copyFileFs } from 'node:fs/promises'\nimport { mkdirp } from 'mkdirp'\nimport { dirname, join } from 'pathe'\nimport type { BrowserCommand } from 'vitest/node'\n\nexport const copyFile: BrowserCommand<[src: string, dest: string]> = async ({ testPath, provider }, src, dest) => {\n\tif (provider.name === 'playwright') {\n\t\tconst destPath = join(dirname(testPath), dest)\n\t\tconst destDir = dirname(destPath)\n\t\tawait mkdirp(destDir)\n\t\treturn copyFileFs(join(dirname(testPath), src), destPath)\n\t}\n\n\tthrow new Error(`provider ${provider.name} is not supported`)\n}\n","import { stat } from 'node:fs/promises'\nimport { dirname, join } from 'pathe'\nimport type { BrowserCommand } from 'vitest/node'\n\nexport const existDir: BrowserCommand<[path: string]> = async ({ testPath, provider }, path) => {\n\tif (provider.name === 'playwright') {\n\t\treturn stat(join(dirname(testPath), path))\n\t\t\t.then((s) => s.isDirectory())\n\t\t\t.catch(() => false)\n\t}\n\n\tthrow new Error(`provider ${provider.name} is not supported`)\n}\n","import { dirname, join } from 'pathe'\nimport { rimraf } from 'rimraf'\nimport type { BrowserCommand } from 'vitest/node'\n\nexport const rmDir: BrowserCommand<[path: string]> = async ({ testPath, provider }, path) => {\n\tif (provider.name === 'playwright') {\n\t\treturn rimraf(join(dirname(testPath), path))\n\t}\n\n\tthrow new Error(`provider ${provider.name} is not supported`)\n}\n","import type { Plugin } from 'vitest/config'\nimport './augment.js'\nimport { copyFile } from './vitest-plugin/commands/copy_file.js'\nimport { existDir } from './vitest-plugin/commands/exist_dir.js'\nimport { rmDir } from './vitest-plugin/commands/rm_dir.js'\n\nexport function storybookVis(): Plugin {\n\treturn {\n\t\tname: 'vitest:storybook-vis',\n\t\tconfig() {\n\t\t\treturn {\n\t\t\t\ttest: {\n\t\t\t\t\tbrowser: {\n\t\t\t\t\t\tname: undefined,\n\t\t\t\t\t\tcommands: {\n\t\t\t\t\t\t\texistDir,\n\t\t\t\t\t\t\tcopyFile,\n\t\t\t\t\t\t\trmDir,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t}\n}\n"]}
@@ -29,6 +29,7 @@ declare module '@vitest/browser/context' {
29
29
  interface BrowserCommands {
30
30
  existDir: (path: string) => Promise<boolean>;
31
31
  copyFile: (src: string, dest: string) => Promise<void>;
32
+ rmDir: (path: string) => Promise<void>;
32
33
  }
33
34
  }
34
35
  declare global {
@@ -87,16 +88,27 @@ declare function shouldTakeSnapshot(ctx: {
87
88
  };
88
89
  }): boolean;
89
90
 
91
+ /**
92
+ * The project parameters for the snapshot.
93
+ *
94
+ * These parameters are set per project in the `.storybook/preview.ts` file.
95
+ */
96
+ type VisOptions = {
97
+ /**
98
+ * The snapshot folder relative to the root of the project.
99
+ */
100
+ snapshotPath: string;
101
+ };
90
102
  declare function configureSnapshotBeforeAll(suite: {
91
103
  file: {
92
104
  filepath: string;
93
105
  };
94
106
  name: string;
95
- }): void;
107
+ }, options?: VisOptions): Promise<void>;
96
108
  declare function configureSnapshotBeforeEach(ctx: {
97
109
  task: {
98
110
  name: string;
99
111
  };
100
112
  }): void;
101
113
 
102
- export { cdp, commands, configureSnapshotBeforeAll, configureSnapshotBeforeEach, page, server, shouldTakeSnapshot, toMatchImageSnapshot };
114
+ export { type VisOptions, cdp, commands, configureSnapshotBeforeAll, configureSnapshotBeforeEach, page, server, shouldTakeSnapshot, toMatchImageSnapshot };
@@ -1,6 +1,6 @@
1
- import {basename,join,dirname,relative}from'pathe';import {getByAltText,getByRole,getByTestId,getByText,getByTitle,getByPlaceholderText,getByLabelText}from'@storybook/test';import A from'dedent';import C from'pixelmatch';var s={name:"",testFilepath:"",taskName:"",snapshot:{}};var g=Symbol.for("storybook-addon-vis/imageSnapshot"),f=Symbol.for("storybook-addon-vis/imageSnapshotStub");function l(t){return new Promise((e,a)=>{let o=new Image;o.src=`data:image/png;base64,${t}`,o.onload=()=>{let n=document.createElement("canvas");n.width=o.width,n.height=o.height;let r=n.getContext("2d");r.drawImage(o,0,0),e(r.getImageData(0,0,n.width,n.height));},o.onerror=()=>{a(new Error("Failed to load image"));};})}async function S(t){let e=document.createElement("canvas");return e.width=t.width,e.height=t.height,e.getContext("2d").putImageData(t,0,0),new Promise(o=>{e.toBlob(n=>{let r=new FileReader;r.onload=()=>{o(r.result);},r.readAsDataURL(n);});})}function u(t){return !!t&&t.type===g}function I(t){if(!u(t))throw new Error("Expected subject to be an image snapshot")}function D(t){return `${t.replace(/[^a-z0-9]/gi,"-").toLowerCase()}`}async function P(t){let e=basename(s.testFilepath),a=`${D(s.taskName)}-${s.snapshot[s.taskName].index++}.png`,o=join(s.baselineDir,e,a),n=join(s.resultDir,e,a),r=join(s.diffDir,e,a),i=await this.screenshot({base64:!0,path:n,element:t?.element}),m=await l(i.base64);return {type:g,testfilename:e,snapshotFilename:a,baselinePath:o,resultPath:n,diffPath:r,base64:i.base64,image:m}}var h;globalThis.__vitest_browser__&&import('@vitest/browser/context').then(t=>{h=t,E.extend({imageSnapshot:P});});function rt(){return h?.cdp()??{}}var d=new Proxy({},{get(t,e){return t[e]??(h?.commands)[e]}}),E=new Proxy({getByAltText:getByAltText,getByRole:getByRole,getByTestId:getByTestId,getByText:getByText,getByTitle:getByTitle,getByPlaceholder:getByPlaceholderText,getByLabelText:getByLabelText},{get(t,e){return t[e]??h?.page?(h?.page)[e]:()=>{if(e==="imageSnapshot")return {type:f};console.info(`\`page.${e.toString()}\` does not exist when running in browser`);}}}),it=new Proxy({},{get(t,e){return t[e]??(h?.server)[e]}});async function dt(t,e){let a=await t;if(a?.type===f)return b;if(!u(a)){if(a?.path&&a?.base64)return {pass:!1,actual:t,message:()=>"`toMatchImageSnapshot()` expects the subject to be the result of `page.imageSnapshot()`, but seems like you are using `page.screenshot()`?"};if(typeof a!="object")return {pass:!1,actual:t,message:()=>`\`toMatchImageSnapshot()\` expects the subject to be an element, locator, or result of \`page.imageSnapshot()\`, but got: \`${t}\``}}I(a);let o=await R(a.baselinePath);if(!o)return await d.copyFile(a.resultPath,a.baselinePath),b;let n=await l(o),[r,i]=M(a.image,n),{pass:m,diffAmount:p,diffImage:c}=U(i,r,e);return m?b:(await z(`${a.diffPath}`,c),{pass:!1,actual:t,message:()=>A`${e?.failureThreshold?e?.failureThresholdType==="percent"?`Expected image to match within ${e.failureThreshold}% but was differ by ${p}%.`:`Expected image to match within ${e.failureThreshold} pixels but was differ by ${p} pixels.`:`Expected image to match but was differ by ${e?.failureThresholdType==="percent"?`${p}%`:`${p} pixels`}.`}
1
+ import {basename,join,dirname,relative}from'pathe';import {getByAltText,getByRole,getByTestId,getByText,getByTitle,getByPlaceholderText,getByLabelText}from'@storybook/test';import A from'dedent';import C from'pixelmatch';var f=Symbol.for("storybook-addon-vis/imageSnapshot"),l=Symbol.for("storybook-addon-vis/imageSnapshotStub");function d(t){return new Promise((e,a)=>{let s=new Image;s.src=`data:image/png;base64,${t}`,s.onload=()=>{let o=document.createElement("canvas");o.width=s.width,o.height=s.height;let r=o.getContext("2d");r.drawImage(s,0,0),e(r.getImageData(0,0,o.width,o.height));},s.onerror=()=>{a(new Error("Failed to load image"));};})}async function S(t){let e=document.createElement("canvas");return e.width=t.width,e.height=t.height,e.getContext("2d").putImageData(t,0,0),new Promise(s=>{e.toBlob(o=>{let r=new FileReader;r.onload=()=>{s(r.result);},r.readAsDataURL(o);});})}var n={name:"",testFilepath:"",taskName:"",snapshot:{}};function u(t){return !!t&&t.type===f}function I(t){if(!u(t))throw new Error("Expected subject to be an image snapshot")}function D(t){return `${t.replace(/[^a-z0-9]/gi,"-").toLowerCase()}`}async function P(t){let e=basename(n.testFilepath),a=`${D(n.taskName)}-${n.snapshot[n.taskName].index++}.png`,s=join(n.baselineDir,e,a),o=join(n.resultDir,e,a),r=join(n.diffDir,e,a),i=await this.screenshot({base64:!0,path:o,element:t?.element}),m=await d(i.base64);return {type:f,testfilename:e,snapshotFilename:a,baselinePath:s,resultPath:o,diffPath:r,base64:i.base64,image:m}}var c;globalThis.__vitest_browser__&&import('@vitest/browser/context').then(t=>{c=t,E.extend({imageSnapshot:P});});function rt(){return c?.cdp()??{}}var h=new Proxy({},{get(t,e){return t[e]??(c?.commands)[e]}}),E=new Proxy({getByAltText:getByAltText,getByRole:getByRole,getByTestId:getByTestId,getByText:getByText,getByTitle:getByTitle,getByPlaceholder:getByPlaceholderText,getByLabelText:getByLabelText},{get(t,e){return t[e]??c?.page?(c?.page)[e]:()=>{if(e==="imageSnapshot")return {type:l};console.info(`\`page.${e.toString()}\` does not exist when running in browser`);}}}),it=new Proxy({},{get(t,e){return t[e]??(c?.server)[e]}});async function dt(t,e){let a=await t;if(a?.type===l)return b;if(!u(a)){if(a?.path&&a?.base64)return {pass:!1,actual:t,message:()=>"`toMatchImageSnapshot()` expects the subject to be the result of `page.imageSnapshot()`, but seems like you are using `page.screenshot()`?"};if(typeof a!="object")return {pass:!1,actual:t,message:()=>`\`toMatchImageSnapshot()\` expects the subject to be an element, locator, or result of \`page.imageSnapshot()\`, but got: \`${t}\``}}I(a);let s=await R(a.baselinePath);if(!s)return await h.copyFile(a.resultPath,a.baselinePath),b;let o=await d(s),[r,i]=M(a.image,o),{pass:m,diffAmount:p,diffImage:g}=U(i,r,e);return m?b:(await z(`${a.diffPath}`,g),{pass:!1,actual:t,message:()=>A`${e?.failureThreshold?e?.failureThresholdType==="percent"?`Expected image to match within ${e.failureThreshold}% but was differ by ${p}%.`:`Expected image to match within ${e.failureThreshold} pixels but was differ by ${p} pixels.`:`Expected image to match but was differ by ${e?.failureThresholdType==="percent"?`${p}%`:`${p} pixels`}.`}
2
2
 
3
3
  Expected: '${a.baselinePath}'
4
4
  Actual: '${a.resultPath}'
5
- Difference: '${a.diffPath}'`})}var b={pass:!0,message:()=>""};function R(t){return d.readFile(t,{encoding:"base64"}).catch(()=>{})}async function z(t,e){let a=(await S(e)).split(",")[1];return d.writeFile(t,a,"base64url")}function M(t,e){if(O(t,e))return [t,e];let a=N(t,e),o=L(a);return [o(t),o(e)]}function N(t,e){let a=Math.max(t.width,e.width),o=Math.max(t.height,e.height);return {width:a,height:o}}function O(t,e){return t.width===e.width&&t.height===e.height}var L=({width:t,height:e})=>a=>{if(a.width===t&&a.height===e)return a;let o=(r,i)=>i<=a.height&&r<=a.width,n=new ImageData(t,e,{colorSpace:a.colorSpace});for(let r=0;r<e;r++)for(let i=0;i<t;i++){let m=t*r+i<<2;if(o(i,r)){let p=a.width*r+i<<2;n.data[m]=a.data[p],n.data[m+1]=a.data[p+1],n.data[m+2]=a.data[p+2],n.data[m+3]=a.data[p+3];}else n.data[m]=0,n.data[m+1]=0,n.data[m+2]=0,n.data[m+3]=64;}return n};function U(t,e,{failureThreshold:a=0,failureThresholdType:o="pixel",diffOptions:n}={}){let{width:r,height:i}=e,m=new ImageData(r,i),p=C(e.data,t.data,m.data,r,i,n),c=q({failureThresholdType:o,width:r,height:i},p);return {pass:c<=a,diffAmount:c,diffImage:m}}function q({failureThresholdType:t,width:e,height:a},o){switch(t){case"pixel":return o;case"percent":return o/(e*a)*100;default:throw new Error(`Invalid failureThresholdType: ${t}`)}}function yt(t){return t.story?.tags?t.story.tags.lastIndexOf("!snapshot")<t.story.tags.lastIndexOf("snapshot"):!1}function St(t){s.name=t.name,s.testFilepath=t.file.filepath,s.testFilename=basename(s.testFilepath),s.projectDir=s.testFilepath.slice(0,-s.name.length);let e=dirname(s.testFilepath);s.baselineDir=relative(e,join(s.projectDir,"__snapshots__")),s.resultDir=relative(e,join(s.projectDir,"__snapshots__","__results__")),s.diffDir=relative(e,join(s.projectDir,"__snapshots__","__diff_output__"));}function It(t){s.taskName=t.task.name,s.snapshot[s.taskName]=s.snapshot[s.taskName]??{index:1};}export{rt as cdp,d as commands,St as configureSnapshotBeforeAll,It as configureSnapshotBeforeEach,E as page,it as server,yt as shouldTakeSnapshot,dt as toMatchImageSnapshot};//# sourceMappingURL=vitest-setup.js.map
5
+ Difference: '${a.diffPath}'`})}var b={pass:!0,message:()=>""};function R(t){return h.readFile(t,{encoding:"base64"}).catch(()=>{})}async function z(t,e){let a=(await S(e)).split(",")[1];return h.writeFile(t,a,"base64url")}function M(t,e){if(N(t,e))return [t,e];let a=O(t,e),s=L(a);return [s(t),s(e)]}function O(t,e){let a=Math.max(t.width,e.width),s=Math.max(t.height,e.height);return {width:a,height:s}}function N(t,e){return t.width===e.width&&t.height===e.height}var L=({width:t,height:e})=>a=>{if(a.width===t&&a.height===e)return a;let s=(r,i)=>i<=a.height&&r<=a.width,o=new ImageData(t,e,{colorSpace:a.colorSpace});for(let r=0;r<e;r++)for(let i=0;i<t;i++){let m=t*r+i<<2;if(s(i,r)){let p=a.width*r+i<<2;o.data[m]=a.data[p],o.data[m+1]=a.data[p+1],o.data[m+2]=a.data[p+2],o.data[m+3]=a.data[p+3];}else o.data[m]=0,o.data[m+1]=0,o.data[m+2]=0,o.data[m+3]=64;}return o};function U(t,e,{failureThreshold:a=0,failureThresholdType:s="pixel",diffOptions:o}={}){let{width:r,height:i}=e,m=new ImageData(r,i),p=C(e.data,t.data,m.data,r,i,o),g=V({failureThresholdType:s,width:r,height:i},p);return {pass:g<=a,diffAmount:g,diffImage:m}}function V({failureThresholdType:t,width:e,height:a},s){switch(t){case"pixel":return s;case"percent":return s/(e*a)*100;default:throw new Error(`Invalid failureThresholdType: ${t}`)}}function yt(t){return t.story?.tags?t.story.tags.lastIndexOf("!snapshot")<t.story.tags.lastIndexOf("snapshot"):!1}async function It(t,e){n.name=t.name,n.testFilepath=t.file.filepath,n.testFilename=basename(n.testFilepath),n.projectDir=n.testFilepath.slice(0,-n.name.length);let a=e?.snapshotPath??join(n.projectDir,"__snapshots__"),s=dirname(n.testFilepath);n.baselineDir=relative(s,a),n.resultDir=relative(s,join(a,"__results__")),n.diffDir=relative(s,join(a,"__diff_output__")),await h.rmDir(n.resultDir),await h.rmDir(n.diffDir);}function Dt(t){n.taskName=t.task.name,n.snapshot[n.taskName]=n.snapshot[n.taskName]??{index:1};}export{rt as cdp,h as commands,It as configureSnapshotBeforeAll,Dt as configureSnapshotBeforeEach,E as page,it as server,yt as shouldTakeSnapshot,dt as toMatchImageSnapshot};//# sourceMappingURL=vitest-setup.js.map
6
6
  //# sourceMappingURL=vitest-setup.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/state.ts","../src/@vitest/browser/constants.ts","../src/image_data.ts","../src/@vitest/browser/image_snapshot.logic.ts","../src/@vitest/browser/page.image_snapshot.ts","../src/@vitest/browser/context.ts","../src/expect.to_match_image_snapshot.ts","../src/tags.ts","../src/vitest-setup.ts"],"names":["state","imageSnapshotSymbol","imageSnapshotStubSymbol","toImageData","base64","resolve","reject","img","canvas","ctx","toDataURL","imageData","blob","reader","isImageSnapshot","subject","assertImageSnapshot","toSnapshotId","taskName","imageSnapshot","options","testfilename","basename","snapshotFilename","baselinePath","join","resultPath","diffPath","screenshot","image","m","page","cdp","commands","target","prop","getByAltText","getByRole","getByTestId","getByText","getByTitle","getByPlaceholderText","getByLabelText","server","toMatchImageSnapshot","actual","success","baseline","tryReadSnapshot","originalImage","resultImage","baselineImage","alignImagesToSameSize","pass","diffAmount","diffImage","compareImage","writeSnapshot","dedent","path","content","image1","image2","isSameSize","size","getMaxSize","resize","createImageResizer","width","height","inArea","x","y","result","idx","old","failureThreshold","failureThresholdType","diffOptions","pixelDiff","pixelmatch","toThresholdUnit","shouldTakeSnapshot","configureSnapshotBeforeAll","suite","currentDir","dirname","relative","configureSnapshotBeforeEach"],"mappings":"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","file":"vitest-setup.js","sourcesContent":["export const state = {\n\tname: '',\n\ttestFilepath: '',\n\ttaskName: '',\n\tsnapshot: {},\n} as {\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\tsnapshot: Record<string, { index: number }>\n}\n","export const imageSnapshotSymbol = Symbol.for('storybook-addon-vis/imageSnapshot')\n\nexport const imageSnapshotStubSymbol = Symbol.for('storybook-addon-vis/imageSnapshotStub')\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 { 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 type { BrowserPage } from '@vitest/browser/context'\nimport { basename, join } from 'pathe'\nimport { toImageData } from '../../image_data.js'\nimport { state } from '../../state.js'\nimport { imageSnapshotSymbol } from './constants.js'\nimport { toSnapshotId } from './image_snapshot.logic.js'\nimport type { ImageSnapshot, ImageSnapshotOptions } from './types.js'\n\nexport async function imageSnapshot(this: BrowserPage, options?: ImageSnapshotOptions): Promise<ImageSnapshot> {\n\t// const rootDir = server.config.root\n\tconst testfilename = basename(state.testFilepath)\n\tconst snapshotFilename = `${toSnapshotId(state.taskName)}-${state.snapshot[state.taskName]!.index++}.png`\n\tconst baselinePath = join(state.baselineDir, testfilename, snapshotFilename)\n\tconst resultPath = join(state.resultDir, testfilename, snapshotFilename)\n\tconst diffPath = join(state.diffDir, testfilename, snapshotFilename)\n\tconst screenshot = await this.screenshot({\n\t\tbase64: true,\n\t\tpath: resultPath,\n\t\telement: options?.element,\n\t})\n\tconst image = await toImageData(screenshot.base64)\n\n\treturn {\n\t\ttype: imageSnapshotSymbol,\n\t\t// rootDir,\n\t\ttestfilename,\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 { 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 })\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() ?? {}\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\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","import type { AsyncExpectationResult } from '@vitest/expect'\nimport dedent from 'dedent'\nimport pixelmatch from 'pixelmatch'\nimport { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'\nimport { commands } from './@vitest/browser/context.js'\nimport { assertImageSnapshot, isImageSnapshot } from './@vitest/browser/image_snapshot.logic.js'\nimport type { MatchImageSnapshotOptions } from './@vitest/browser/types.js'\nimport { toDataURL, toImageData } from './image_data.js'\n\nexport async function toMatchImageSnapshot(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tconst 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,\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,\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: \\`${actual}\\``,\n\t\t\t}\n\t\t}\n\t\t// subject = await page.imageSnapshot({ element: actual })\n\t}\n\tassertImageSnapshot(subject)\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\tconst { pass, diffAmount, diffImage } = compareImage(baselineImage, resultImage, options)\n\tif (!pass) {\n\t\tawait writeSnapshot(`${subject.diffPath}`, diffImage)\n\t\treturn {\n\t\t\tpass: false,\n\t\t\tactual,\n\t\t\tmessage: () =>\n\t\t\t\tdedent`${\n\t\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\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\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\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\nconst 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\t\treturn result\n\t}\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","/**\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 { state } from './state.js'\n\nexport * from './@vitest/browser/context.js'\nexport * from './expect.to_match_image_snapshot.js'\nexport * from './tags.js'\n\nexport function configureSnapshotBeforeAll(suite: { file: { filepath: string }; name: string }) {\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 currentDir = dirname(state.testFilepath)\n\tstate.baselineDir = relative(currentDir, join(state.projectDir, '__snapshots__'))\n\tstate.resultDir = relative(currentDir, join(state.projectDir, '__snapshots__', '__results__'))\n\tstate.diffDir = relative(currentDir, join(state.projectDir, '__snapshots__', '__diff_output__'))\n}\n\nexport function configureSnapshotBeforeEach(ctx: { task: { name: string } }) {\n\tstate.taskName = ctx.task.name\n\tstate.snapshot[state.taskName] = state.snapshot[state.taskName] ?? { index: 1 }\n}\n"]}
1
+ {"version":3,"sources":["../src/@vitest/browser/constants.ts","../src/@vitest/browser/page.image_snapshot.ts","../src/image_data.ts","../src/state.ts","../src/@vitest/browser/image_snapshot.logic.ts","../src/@vitest/browser/context.ts","../src/expect.to_match_image_snapshot.ts","../src/tags.ts","../src/vitest-setup.ts"],"names":["imageSnapshotSymbol","imageSnapshotStubSymbol","toImageData","base64","resolve","reject","img","canvas","ctx","toDataURL","imageData","blob","reader","state","isImageSnapshot","subject","assertImageSnapshot","toSnapshotId","taskName","imageSnapshot","options","testfilename","basename","snapshotFilename","baselinePath","join","resultPath","diffPath","screenshot","image","m","page","cdp","commands","target","prop","getByAltText","getByRole","getByTestId","getByText","getByTitle","getByPlaceholderText","getByLabelText","server","toMatchImageSnapshot","actual","success","baseline","tryReadSnapshot","originalImage","resultImage","baselineImage","alignImagesToSameSize","pass","diffAmount","diffImage","compareImage","writeSnapshot","dedent","path","content","image1","image2","isSameSize","size","getMaxSize","resize","createImageResizer","width","height","inArea","x","y","result","idx","old","failureThreshold","failureThresholdType","diffOptions","pixelDiff","pixelmatch","toThresholdUnit","shouldTakeSnapshot","configureSnapshotBeforeAll","suite","snapshotPath","currentDir","dirname","relative","configureSnapshotBeforeEach"],"mappings":"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","file":"vitest-setup.js","sourcesContent":["export const imageSnapshotSymbol = Symbol.for('storybook-addon-vis/imageSnapshot')\n\nexport const imageSnapshotStubSymbol = Symbol.for('storybook-addon-vis/imageSnapshotStub')\n","import type { BrowserPage } from '@vitest/browser/context'\nimport { basename, join } from 'pathe'\nimport { toImageData } from '../../image_data.js'\nimport { state } from '../../state.js'\nimport { imageSnapshotSymbol } from './constants.js'\nimport { toSnapshotId } from './image_snapshot.logic.js'\nimport type { ImageSnapshot, ImageSnapshotOptions } from './types.js'\n\nexport async function imageSnapshot(this: BrowserPage, options?: ImageSnapshotOptions): Promise<ImageSnapshot> {\n\t// const rootDir = server.config.root\n\tconst testfilename = basename(state.testFilepath)\n\tconst snapshotFilename = `${toSnapshotId(state.taskName)}-${state.snapshot[state.taskName]!.index++}.png`\n\tconst baselinePath = join(state.baselineDir, testfilename, snapshotFilename)\n\tconst resultPath = join(state.resultDir, testfilename, snapshotFilename)\n\tconst diffPath = join(state.diffDir, testfilename, snapshotFilename)\n\tconst screenshot = await this.screenshot({\n\t\tbase64: true,\n\t\tpath: resultPath,\n\t\telement: options?.element,\n\t})\n\tconst image = await toImageData(screenshot.base64)\n\n\treturn {\n\t\ttype: imageSnapshotSymbol,\n\t\t// rootDir,\n\t\ttestfilename,\n\t\tsnapshotFilename,\n\t\tbaselinePath,\n\t\tresultPath,\n\t\tdiffPath,\n\t\tbase64: screenshot.base64,\n\t\timage,\n\t}\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","export const state = {\n\tname: '',\n\ttestFilepath: '',\n\ttaskName: '',\n\tsnapshot: {},\n} as {\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\tsnapshot: Record<string, { index: number }>\n}\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 {\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 { 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 })\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() ?? {}\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\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","import type { AsyncExpectationResult } from '@vitest/expect'\nimport dedent from 'dedent'\nimport pixelmatch from 'pixelmatch'\nimport { imageSnapshotStubSymbol } from './@vitest/browser/constants.js'\nimport { commands } from './@vitest/browser/context.js'\nimport { assertImageSnapshot, isImageSnapshot } from './@vitest/browser/image_snapshot.logic.js'\nimport type { MatchImageSnapshotOptions } from './@vitest/browser/types.js'\nimport { toDataURL, toImageData } from './image_data.js'\n\nexport async function toMatchImageSnapshot(\n\tactual: any,\n\toptions?: MatchImageSnapshotOptions | undefined,\n): AsyncExpectationResult {\n\tconst 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,\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,\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: \\`${actual}\\``,\n\t\t\t}\n\t\t}\n\t\t// subject = await page.imageSnapshot({ element: actual })\n\t}\n\tassertImageSnapshot(subject)\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\tconst { pass, diffAmount, diffImage } = compareImage(baselineImage, resultImage, options)\n\tif (!pass) {\n\t\tawait writeSnapshot(`${subject.diffPath}`, diffImage)\n\t\treturn {\n\t\t\tpass: false,\n\t\t\tactual,\n\t\t\tmessage: () =>\n\t\t\t\tdedent`${\n\t\t\t\t\toptions?.failureThreshold\n\t\t\t\t\t\t? options?.failureThresholdType === 'percent'\n\t\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\t: `Expected image to match within ${options.failureThreshold} pixels but was differ by ${diffAmount} pixels.`\n\t\t\t\t\t\t: `Expected image to match but was differ by ${options?.failureThresholdType === 'percent' ? `${diffAmount}%` : `${diffAmount} pixels`}.`\n\t\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\nconst 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\t\treturn result\n\t}\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","/**\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 { 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 = options?.snapshotPath ?? join(state.projectDir, '__snapshots__')\n\tconst currentDir = dirname(state.testFilepath)\n\tstate.baselineDir = relative(currentDir, snapshotPath)\n\tstate.resultDir = relative(currentDir, join(snapshotPath, '__results__'))\n\tstate.diffDir = relative(currentDir, join(snapshotPath, '__diff_output__'))\n\tawait commands.rmDir(state.resultDir)\n\tawait commands.rmDir(state.diffDir)\n}\n\nexport function configureSnapshotBeforeEach(ctx: { task: { name: string } }) {\n\tstate.taskName = ctx.task.name\n\tstate.snapshot[state.taskName] = state.snapshot[state.taskName] ?? { index: 1 }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storybook-addon-vis",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Storybook Vitest Image Snapshot addon",
5
5
  "keywords": [
6
6
  "image-snapshot",
@@ -55,6 +55,7 @@
55
55
  "mkdirp": "^3.0.1",
56
56
  "pathe": "^1.1.2",
57
57
  "pixelmatch": "^6.0.0",
58
+ "rimraf": "^6.0.1",
58
59
  "type-plus": "^8.0.0-beta.6"
59
60
  },
60
61
  "devDependencies": {
package/readme.md CHANGED
@@ -33,8 +33,8 @@ On [vitest], you need to add `storybook-addon-vis/vitest-plugin` plugin in `vite
33
33
  ```ts
34
34
  // vite.config.ts or vitest.config.ts
35
35
  import { storybookTest } from '@storybook/experimental-addon-test/vitest-plugin'
36
- import { defineConfig } from 'vitest/config'
37
36
  import { storybookVis } from 'storybook-addon-vis/vitest-plugin'
37
+ import { defineConfig } from 'vitest/config'
38
38
 
39
39
  export default defineConfig({
40
40
  plugins: [
@@ -57,23 +57,23 @@ In `vitest.setup.ts`, you need to extend [vitest] `expect` and register lifecycl
57
57
  ```ts
58
58
  // vitest.setup.ts
59
59
  import { type StoryContext, setProjectAnnotations } from '@storybook/react'
60
- import { afterEach, beforeAll, beforeEach, expect } from 'vitest'
61
60
  import {
62
61
  configureSnapshotBeforeAll,
63
62
  configureSnapshotBeforeEach,
64
63
  page,
65
64
  shouldTakeSnapshot,
66
65
  toMatchImageSnapshot,
67
- } from 'storybook-addon-vis/vitest-setup.js'
66
+ } from 'storybook-addon-vis/vitest-setup'
67
+ import { afterEach, beforeAll, beforeEach, expect } from 'vitest'
68
68
  import * as projectAnnotations from './preview'
69
69
 
70
70
  const project = setProjectAnnotations([projectAnnotations])
71
71
 
72
72
  expect.extend({ toMatchImageSnapshot })
73
73
 
74
- beforeAll((suite) => {
74
+ beforeAll(async (suite) => {
75
75
  project.beforeAll()
76
- configureSnapshotBeforeAll(suite)
76
+ await configureSnapshotBeforeAll(suite, /* optional options */)
77
77
  })
78
78
 
79
79
  beforeEach(configureSnapshotBeforeEach)
@@ -90,7 +90,7 @@ On [storybook], you need to extend the `expect` from `@storybook/test`
90
90
  ```ts
91
91
  // .storybook/preview.tsx
92
92
  import { expect } from '@storybook/test'
93
- import { toMatchImageSnapshot } from '../src/index.js'
93
+ import { toMatchImageSnapshot } from 'storybook-addon-vis'
94
94
 
95
95
  expect.extend({ toMatchImageSnapshot })
96
96
 
@@ -138,13 +138,15 @@ export const MyStory = {
138
138
  Besides automatic snapshot, you can capture image snapshot manually.
139
139
 
140
140
  ```ts
141
- import { page } from 'storybook-addon-vis'
142
141
  import { expect } from '@storybook/test'
143
142
 
143
+ // `page` and the like are proxy to `@vitest/browser/context` to work in storybook
144
+ import { page } from 'storybook-addon-vis'
145
+
144
146
  export const PageSnapshot = {
145
147
  // ...
146
148
  async play() {
147
- expect(page.imageSnapshot()).toMatchImageSnapshot()
149
+ await expect(page.imageSnapshot()).toMatchImageSnapshot()
148
150
  }
149
151
  }
150
152
 
@@ -160,4 +162,4 @@ export const ElementSnapshot = {
160
162
  [jest-image-snapshot]: https://github.com/americanexpress/jest-image-snapshot
161
163
  [storybook-addon-vis]: https://github.com/repobuddy/storybook-addon-vis
162
164
  [storybook]: https://storybook.js.org
163
- [vitest]: https://vitest.dev/
165
+ [vitest]: https://vitest.dev/
package/src/augment.ts CHANGED
@@ -9,6 +9,7 @@ declare module '@vitest/browser/context' {
9
9
  interface BrowserCommands {
10
10
  existDir: (path: string) => Promise<boolean>
11
11
  copyFile: (src: string, dest: string) => Promise<void>
12
+ rmDir: (path: string) => Promise<void>
12
13
  }
13
14
  }
14
15
 
package/src/param.spec.ts CHANGED
@@ -1,35 +1,4 @@
1
- // import {it}from 'vitest'
2
-
3
- import type { Preview } from '@storybook/react'
4
- import { defineSnapshotParam, defineSnapshotProjectParam } from './param'
5
-
6
- describe(`${defineSnapshotProjectParam.name}()`, () => {
7
- it.todo('can define the snapshot root folder relative to the root of the project', () => {
8
- const preview: Preview = {
9
- parameters: defineSnapshotProjectParam({
10
- snapshotPath: './_sp_',
11
- }),
12
- }
13
- expect(preview).toEqual({
14
- snapshotPath: './_sp_',
15
- })
16
- })
17
-
18
- it.todo('can define the baseline, result, and diff folders relative to the snapshot root folder', () => {
19
- const preview: Preview = {
20
- parameters: defineSnapshotProjectParam({
21
- baseline: 'baseline',
22
- result: 'result',
23
- diff: 'diff',
24
- }),
25
- }
26
- expect(preview).toEqual({
27
- baseline: 'baseline',
28
- result: 'result',
29
- diff: 'diff',
30
- })
31
- })
32
- })
1
+ import { defineSnapshotParam } from './param'
33
2
 
34
3
  describe(`${defineSnapshotParam.name}()`, () => {
35
4
  it.todo('can define the comparison method for snapshots', () => {
package/src/param.ts CHANGED
@@ -1,37 +1,5 @@
1
1
  import type { PixelmatchOptions } from 'pixelmatch'
2
2
 
3
- /**
4
- * The project parameters for the snapshot.
5
- *
6
- * These parameters are set per project in the `.storybook/preview.ts` file.
7
- */
8
- export type SnapshotProjectParam = {
9
- /**
10
- * The snapshot folder relative to the root of the project.
11
- */
12
- snapshotPath: string
13
- /**
14
- * The baseline folder under the snapshot folder specified in `snapshotPath`.
15
- */
16
- baseline: string
17
- /**
18
- * The result folder under the snapshot folder specified in `snapshotPath`.
19
- *
20
- * This folder stores the snapshot of the current test run.
21
- */
22
- result: string
23
- /**
24
- * The diff folder under the snapshot folder specified in `snapshotPath`.
25
- *
26
- * This folder stores the diff of the current test run if the test fails.
27
- */
28
- diff: string
29
- }
30
-
31
- export function defineSnapshotProjectParam(snapshot: Partial<SnapshotProjectParam>) {
32
- return { snapshot }
33
- }
34
-
35
3
  export type SnapshotStoryParam = {
36
4
  /**
37
5
  * Add a delay to the story snapshot comparison to allow for async rendering.
@@ -0,0 +1,11 @@
1
+ import { dirname, join } from 'pathe'
2
+ import { rimraf } from 'rimraf'
3
+ import type { BrowserCommand } from 'vitest/node'
4
+
5
+ export const rmDir: BrowserCommand<[path: string]> = async ({ testPath, provider }, path) => {
6
+ if (provider.name === 'playwright') {
7
+ return rimraf(join(dirname(testPath), path))
8
+ }
9
+
10
+ throw new Error(`provider ${provider.name} is not supported`)
11
+ }
@@ -2,6 +2,7 @@ import type { Plugin } from 'vitest/config'
2
2
  import './augment.js'
3
3
  import { copyFile } from './vitest-plugin/commands/copy_file.js'
4
4
  import { existDir } from './vitest-plugin/commands/exist_dir.js'
5
+ import { rmDir } from './vitest-plugin/commands/rm_dir.js'
5
6
 
6
7
  export function storybookVis(): Plugin {
7
8
  return {
@@ -14,6 +15,7 @@ export function storybookVis(): Plugin {
14
15
  commands: {
15
16
  existDir,
16
17
  copyFile,
18
+ rmDir,
17
19
  },
18
20
  },
19
21
  },
@@ -3,12 +3,28 @@ import { basename } from 'pathe'
3
3
  import { expect, it } from 'vitest'
4
4
  import { commands, page } from './@vitest/browser/context.js'
5
5
  import * as ImageDataStories from './image_data.stories.js'
6
+ import { state } from './state.js'
7
+ import { configureSnapshotBeforeAll } from './vitest-setup.js'
6
8
 
7
9
  const { ConversionRoundtrip } = composeStories(ImageDataStories)
8
10
 
9
- it.todo('should delete the results and diffs folder when the during `beforeAll`', async ({ task }) => {
11
+ it('should delete the results and diffs folder when the during `beforeAll`', async ({ task }) => {
10
12
  await expect(commands.existDir(`../__snapshots__/__diff_output__/${basename(task.file.name)}`)).resolves.toBe(false)
11
13
  await expect(commands.existDir(`../__snapshots__/__results__/${basename(task.file.name)}`)).resolves.toBe(false)
12
14
  await ConversionRoundtrip.run()
13
15
  await expect(page.imageSnapshot()).toMatchImageSnapshot()
14
16
  })
17
+
18
+ it('can define the snapshot root folder relative to the root of the project', async () => {
19
+ await configureSnapshotBeforeAll(
20
+ { name: 'name', file: { filepath: 'dummy/path' } },
21
+ {
22
+ snapshotPath: '_sp_',
23
+ },
24
+ ),
25
+ expect(state).toMatchObject({
26
+ baselineDir: '../_sp_',
27
+ diffDir: '../_sp_/__diff_output__',
28
+ resultDir: '../_sp_/__results__',
29
+ })
30
+ })
@@ -1,20 +1,39 @@
1
1
  import { basename, dirname, join, relative } from 'pathe'
2
2
  import './augment.js'
3
+ import { commands } from './@vitest/browser/context.js'
3
4
  import { state } from './state.js'
4
5
 
5
6
  export * from './@vitest/browser/context.js'
6
7
  export * from './expect.to_match_image_snapshot.js'
7
8
  export * from './tags.js'
8
9
 
9
- export function configureSnapshotBeforeAll(suite: { file: { filepath: string }; name: string }) {
10
+ /**
11
+ * The project parameters for the snapshot.
12
+ *
13
+ * These parameters are set per project in the `.storybook/preview.ts` file.
14
+ */
15
+ export type VisOptions = {
16
+ /**
17
+ * The snapshot folder relative to the root of the project.
18
+ */
19
+ snapshotPath: string
20
+ }
21
+
22
+ export async function configureSnapshotBeforeAll(
23
+ suite: { file: { filepath: string }; name: string },
24
+ options?: VisOptions,
25
+ ) {
10
26
  state.name = suite.name
11
27
  state.testFilepath = suite.file.filepath
12
28
  state.testFilename = basename(state.testFilepath)
13
29
  state.projectDir = state.testFilepath.slice(0, -state.name.length)
30
+ const snapshotPath = options?.snapshotPath ?? join(state.projectDir, '__snapshots__')
14
31
  const currentDir = dirname(state.testFilepath)
15
- state.baselineDir = relative(currentDir, join(state.projectDir, '__snapshots__'))
16
- state.resultDir = relative(currentDir, join(state.projectDir, '__snapshots__', '__results__'))
17
- state.diffDir = relative(currentDir, join(state.projectDir, '__snapshots__', '__diff_output__'))
32
+ state.baselineDir = relative(currentDir, snapshotPath)
33
+ state.resultDir = relative(currentDir, join(snapshotPath, '__results__'))
34
+ state.diffDir = relative(currentDir, join(snapshotPath, '__diff_output__'))
35
+ await commands.rmDir(state.resultDir)
36
+ await commands.rmDir(state.diffDir)
18
37
  }
19
38
 
20
39
  export function configureSnapshotBeforeEach(ctx: { task: { name: string } }) {