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 +2 -31
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/vitest-plugin.d.ts +1 -0
- package/dist/vitest-plugin.js +1 -1
- package/dist/vitest-plugin.js.map +1 -1
- package/dist/vitest-setup.d.ts +14 -2
- package/dist/vitest-setup.js +2 -2
- package/dist/vitest-setup.js.map +1 -1
- package/package.json +2 -1
- package/readme.md +11 -9
- package/src/augment.ts +1 -0
- package/src/param.spec.ts +1 -32
- package/src/param.ts +0 -32
- package/src/vitest-plugin/commands/rm_dir.ts +11 -0
- package/src/vitest-plugin.ts +2 -0
- package/src/vitest-setup.spec.ts +17 -1
- package/src/vitest-setup.ts +23 -4
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
|
|
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}}
|
|
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"]}
|
package/dist/vitest-plugin.d.ts
CHANGED
package/dist/vitest-plugin.js
CHANGED
|
@@ -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
|
|
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":"
|
|
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"]}
|
package/dist/vitest-setup.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 {
|
|
@@ -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 };
|
package/dist/vitest-setup.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
package/dist/vitest-setup.js.map
CHANGED
|
@@ -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.
|
|
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
|
|
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 '
|
|
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
package/src/param.spec.ts
CHANGED
|
@@ -1,35 +1,4 @@
|
|
|
1
|
-
|
|
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
|
+
}
|
package/src/vitest-plugin.ts
CHANGED
|
@@ -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
|
},
|
package/src/vitest-setup.spec.ts
CHANGED
|
@@ -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
|
|
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
|
+
})
|
package/src/vitest-setup.ts
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
16
|
-
state.resultDir = relative(currentDir, join(
|
|
17
|
-
state.diffDir = relative(currentDir, join(
|
|
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 } }) {
|