storybook-addon-vis 3.1.1 → 3.1.3
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.js.map +1 -1
- package/dist/manager.js +21 -15
- package/dist/manager.js.map +1 -1
- package/dist/vis_annotation-DqZTkmEN.js.map +1 -1
- package/dist/vitest-setup.d.ts +2 -2
- package/dist/vitest-setup.d.ts.map +1 -1
- package/dist/vitest-setup.js +1 -1
- package/dist/vitest-setup.js.map +1 -1
- package/package.json +13 -13
- package/src/components/vis_panel.tsx +15 -4
- package/src/manager.tsx +11 -23
- package/src/vitest-setup.ts +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/client/ctx.ts","../src/client/has_image_snapshot.ts","../src/client/storybook/param.ts","../src/index.ts"],"sourcesContent":["import { getCurrentTest } from './vitest_proxy.ts'\n\nexport const ctx = {\n\tgetCurrentTest,\n\t__test__reset() {\n\t\tctx.getCurrentTest = getCurrentTest\n\t},\n}\n","import { hasImageSnapshotAction, toTaskId, type ImageSnapshotKeyOptions } from 'vitest-plugin-vis/client-api'\nimport { ctx } from './ctx.ts'\nimport { commands } from './vitest_proxy.ts'\n\n/**\n * Check if the snapshot image exists.\n */\nexport function hasImageSnapshot(options?: ImageSnapshotKeyOptions | undefined) {\n\tconst test = ctx.getCurrentTest()\n\tif (!test) return false\n\n\treturn hasImageSnapshotAction(commands, toTaskId(test), options)\n}\n","import type {\n\tComparisonMethod,\n\tFailureThresholdOptions,\n\tImageSnapshotCompareOptions,\n\tImageSnapshotKeyOptions,\n\tImageSnapshotSubjectOptions,\n\tImageSnapshotTimeoutOptions,\n\tPixelComparisonOptions,\n\tSsimComparisonOptions,\n\tToMatchImageSnapshotOptions,\n} from 'vitest-plugin-vis/client-api'\n\n// This fix the inferred type cannot be named error\nexport type {\n\tComparisonMethod,\n\tFailureThresholdOptions,\n\tImageSnapshotCompareOptions,\n\tImageSnapshotKeyOptions,\n\tImageSnapshotSubjectOptions,\n\tImageSnapshotTimeoutOptions,\n\tPixelComparisonOptions,\n\tSsimComparisonOptions,\n\tToMatchImageSnapshotOptions,\n}\n\n/**\n * Define snapshot parameter for auto snapshot.\n */\nexport function defineAutoSnapshotParam<M extends ComparisonMethod>(\n\tsnapshot: ToMatchImageSnapshotOptions<M> & ImageSnapshotSubjectOptions,\n) {\n\treturn { snapshot }\n}\n","// `storybook-addon-vis` provides code that can be used in test files.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport { definePreviewAddon } from 'storybook/internal/csf'\nimport { expect } from 'storybook/test'\nimport type { SetupVisOptions } from 'vitest-plugin-vis'\nimport { autoSnapshotMatcher, setAutoSnapshotOptions } from 'vitest-plugin-vis/client-api'\nimport { commands, page } from './client/vitest_proxy.ts'\nimport { visAnnotations } from './preview/vis_annotation.ts'\n\nexport * from 'vitest-plugin-vis'\nexport * from './client/has_image_snapshot.ts'\nexport * from './client/storybook/param.ts'\nexport * from './client/storybook/tags.ts'\n\nexport { page }\n\nexport default (options: SetupVisOptions = { auto: false }) => {\n\tlet matcher: ReturnType<typeof autoSnapshotMatcher>\n\tlet matcherFn: () => Promise<void>\n\treturn definePreviewAddon({\n\t\ttags: options.auto ? ['snapshot'] : [],\n\t\tasync beforeAll() {\n\t\t\tmatcher = autoSnapshotMatcher(commands, expect)\n\t\t\tif (typeof options?.auto === 'function') {\n\t\t\t\tmatcherFn = matcher.createMatcher({\n\t\t\t\t\tauto: options.auto,\n\t\t\t\t})\n\t\t\t} else if (typeof options?.auto === 'object') {\n\t\t\t\tmatcherFn = matcher.createMatcher(options.auto)\n\t\t\t} else matcherFn = matcher.createMatcher({ async auto() {} })\n\n\t\t\tawait matcher.setup()\n\t\t\tawait setAutoSnapshotOptions(true)\n\t\t},\n\t\tafterEach() {\n\t\t\tif (matcherFn) {\n\t\t\t\treturn matcherFn()\n\t\t\t}\n\t\t},\n\t\t...visAnnotations,\n\t})\n}\n"],"mappings":";;;;;;;;AAEA,MAAa,MAAM;CAClB;CACA,gBAAgB;AACf,MAAI,iBAAiB;;CAEtB;;;;;;;ACAD,SAAgB,iBAAiB,SAA+C;CAC/E,MAAM,OAAO,IAAI,gBAAgB;AACjC,KAAI,CAAC,KAAM,QAAO;AAElB,QAAO,uBAAuB,UAAU,SAAS,KAAK,EAAE,QAAQ;;;;;;;;ACiBjE,SAAgB,wBACf,UACC;AACD,QAAO,EAAE,UAAU;;;;;ACbpB,mBAAgB,UAA2B,EAAE,MAAM,OAAO,KAAK;CAC9D,IAAI;CACJ,IAAI;AACJ,QAAO,mBAAmB;EACzB,MAAM,QAAQ,OAAO,CAAC,WAAW,GAAG,EAAE;EACtC,MAAM,YAAY;AACjB,aAAU,oBAAoB,UAAU,OAAO;AAC/C,OAAI,OAAO,SAAS,SAAS,WAC5B,aAAY,QAAQ,cAAc,EACjC,MAAM,QAAQ,MACd,CAAC;YACQ,OAAO,SAAS,SAAS,SACnC,aAAY,QAAQ,cAAc,QAAQ,KAAK;OACzC,aAAY,QAAQ,cAAc,EAAE,MAAM,OAAO,IAAI,CAAC;AAE7D,SAAM,QAAQ,OAAO;AACrB,SAAM,uBAAuB,KAAK;;EAEnC,YAAY;AACX,OAAI,UACH,QAAO,WAAW;;EAGpB,GAAG;EACH,CAAC"}
|
package/dist/manager.js
CHANGED
|
@@ -6,7 +6,11 @@ import { styled } from "storybook/theming";
|
|
|
6
6
|
import { SNAPSHOT_ROOT_DIR } from "vitest-plugin-vis/client-api";
|
|
7
7
|
|
|
8
8
|
//#region src/components/vis_panel.tsx
|
|
9
|
-
const VisPanel = memo(function VisPanel$1({ active,
|
|
9
|
+
const VisPanel = memo(function VisPanel$1({ active, getSnapshotResults, onRefresh }) {
|
|
10
|
+
const [snapshotResults, setSnapshotResults] = useState([]);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
getSnapshotResults().then(setSnapshotResults);
|
|
13
|
+
}, [getSnapshotResults]);
|
|
10
14
|
const groupedResults = snapshotResults.reduce((acc, result) => {
|
|
11
15
|
const key = `(${result.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length + 1)}) ${result.fileName}`;
|
|
12
16
|
acc[key] = [...acc[key] ?? [], result];
|
|
@@ -16,7 +20,10 @@ const VisPanel = memo(function VisPanel$1({ active, snapshotResults = [], onRefr
|
|
|
16
20
|
key: result.filePath,
|
|
17
21
|
src: `data:image/png;base64,${result.base64}`,
|
|
18
22
|
alt: result.fileName
|
|
19
|
-
}))) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SnapshotRow, null, /* @__PURE__ */ React.createElement("span", null, key), /* @__PURE__ */ React.createElement(IconButton, { onClick: () =>
|
|
23
|
+
}))) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SnapshotRow, null, /* @__PURE__ */ React.createElement("span", null, key), /* @__PURE__ */ React.createElement(IconButton, { onClick: () => {
|
|
24
|
+
onRefresh();
|
|
25
|
+
getSnapshotResults().then(setSnapshotResults);
|
|
26
|
+
} }, /* @__PURE__ */ React.createElement(RefreshIcon, null))), /* @__PURE__ */ React.createElement("img", {
|
|
20
27
|
key: results[0].filePath,
|
|
21
28
|
src: `data:image/png;base64,${results[0].base64}`,
|
|
22
29
|
alt: results[0].fileName
|
|
@@ -57,23 +64,22 @@ addons.register(NAME, (api) => {
|
|
|
57
64
|
title: "Vis",
|
|
58
65
|
match: ({ tabId, viewMode }) => !tabId && viewMode === "story",
|
|
59
66
|
render({ active }) {
|
|
60
|
-
|
|
67
|
+
if (!active) return null;
|
|
61
68
|
const storyData = api.getCurrentStoryData();
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
if (!storyData) return null;
|
|
70
|
+
api.emit(NAME, requestImageSnapshotResults(storyData));
|
|
71
|
+
async function getSnapshotResults() {
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
api.once(NAME, (event) => {
|
|
74
|
+
if (event.name !== storyData.name) return;
|
|
75
|
+
if (event.importPath !== storyData.importPath) return;
|
|
76
|
+
if (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) resolve(event.results);
|
|
77
|
+
});
|
|
71
78
|
});
|
|
72
|
-
}
|
|
73
|
-
if (!active) return null;
|
|
79
|
+
}
|
|
74
80
|
return /* @__PURE__ */ React.createElement(VisPanel, {
|
|
75
81
|
active,
|
|
76
|
-
|
|
82
|
+
getSnapshotResults,
|
|
77
83
|
onRefresh: () => {
|
|
78
84
|
if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData));
|
|
79
85
|
}
|
package/dist/manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","names":["VisPanel"],"sources":["../src/components/vis_panel.tsx","../src/shared/contants.ts","../src/shared/events.ts","../src/manager.tsx"],"sourcesContent":["import { RefreshIcon } from '@storybook/icons'\nimport React, { memo } from 'react'\nimport { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'\nimport { styled } from 'storybook/theming'\nimport { SNAPSHOT_ROOT_DIR } from 'vitest-plugin-vis/client-api'\nimport type { ImageSnapshotResults } from '../shared/events.ts'\n\ninterface PanelProps {\n\tactive: boolean\n\
|
|
1
|
+
{"version":3,"file":"manager.js","names":["VisPanel"],"sources":["../src/components/vis_panel.tsx","../src/shared/contants.ts","../src/shared/events.ts","../src/manager.tsx"],"sourcesContent":["import { RefreshIcon } from '@storybook/icons'\nimport React, { memo, useEffect, useState } from 'react'\nimport { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'\nimport { styled } from 'storybook/theming'\nimport { SNAPSHOT_ROOT_DIR } from 'vitest-plugin-vis/client-api'\nimport type { ImageSnapshotResults } from '../shared/events.ts'\n\ninterface PanelProps {\n\tactive: boolean\n\tgetSnapshotResults: () => Promise<ImageSnapshotResults[]>\n\tonRefresh: () => void\n}\n\nexport const VisPanel = memo(function VisPanel({ active, getSnapshotResults, onRefresh }: PanelProps) {\n\tconst [snapshotResults, setSnapshotResults] = useState<ImageSnapshotResults[]>([])\n\n\tuseEffect(() => {\n\t\tgetSnapshotResults().then(setSnapshotResults)\n\t}, [getSnapshotResults])\n\n\tconst groupedResults = snapshotResults.reduce(\n\t\t(acc, result) => {\n\t\t\tconst suiteName = result.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length + 1)\n\t\t\tconst key = `(${suiteName}) ${result.fileName}`\n\t\t\tacc[key] = [...(acc[key] ?? []), result]\n\t\t\treturn acc\n\t\t},\n\t\t{} as Record<string, ImageSnapshotResults[]>,\n\t)\n\treturn (\n\t\t<AddonPanel active={active}>\n\t\t\t{snapshotResults.length > 0 ? (\n\t\t\t\t<ScrollArea vertical>\n\t\t\t\t\t{Object.entries(groupedResults).map(([key, results]) => (\n\t\t\t\t\t\t<div key={key}>\n\t\t\t\t\t\t\t{results.some((result) => result.type === 'diff') ? (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<SnapshotRow failed>{key}</SnapshotRow>\n\t\t\t\t\t\t\t\t\t{results.map((result) => (\n\t\t\t\t\t\t\t\t\t\t<img key={result.filePath} src={`data:image/png;base64,${result.base64}`} alt={result.fileName} />\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<SnapshotRow>\n\t\t\t\t\t\t\t\t\t\t<span>{key}</span>\n\t\t\t\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\tonRefresh()\n\t\t\t\t\t\t\t\t\t\t\t\tgetSnapshotResults().then(setSnapshotResults)\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<RefreshIcon />\n\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t</SnapshotRow>\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tkey={results[0].filePath}\n\t\t\t\t\t\t\t\t\t\tsrc={`data:image/png;base64,${results[0].base64}`}\n\t\t\t\t\t\t\t\t\t\talt={results[0].fileName}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</ScrollArea>\n\t\t\t) : (\n\t\t\t\t<Placeholder>There is no snapshots for this story</Placeholder>\n\t\t\t)}\n\t\t</AddonPanel>\n\t)\n})\n\nconst SnapshotRow = styled.div<{ failed?: boolean }>(({ theme, failed }) => ({\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tgap: '0.5rem',\n\tpaddingBlock: '0.5rem',\n\tpaddingInline: '0.2rem',\n\tbackgroundColor: failed ? theme.background.negative : theme.background.positive,\n\tcolor: theme.barTextColor,\n}))\n","export const NAME = 'storybook-addon-vis'\nexport const VIS_PANEL_ID = `${NAME}/vis_panel`\n","export type VisEvent = ImageSnapshotResultsRequest | ImageSnapshotResultsResponse\n\nexport const IMAGE_SNAPSHOT_RESULTS_REQUEST = 'IMAGE_SNAPSHOT_RESULTS_REQUEST'\nexport const IMAGE_SNAPSHOT_RESULTS_RESPONSE = 'IMAGE_SNAPSHOT_RESULTS_RESPONSE'\n\nexport function requestImageSnapshotResults({ name, importPath }: { name: string; importPath: string }) {\n\treturn {\n\t\ttype: IMAGE_SNAPSHOT_RESULTS_REQUEST,\n\t\tname,\n\t\timportPath,\n\t}\n}\n\nexport type ImageSnapshotResultsRequest = {\n\ttype: typeof IMAGE_SNAPSHOT_RESULTS_REQUEST\n\tname: string\n\timportPath: string\n}\n\nexport type ImageSnapshotResultsResponse = {\n\ttype: typeof IMAGE_SNAPSHOT_RESULTS_RESPONSE\n\tname: string\n\timportPath: string\n\tresults: ImageSnapshotResults[]\n}\n\nexport type ImageSnapshotResults = {\n\tfilePath: string\n\tfileName: string\n\tsnapshotRootDir: string\n\ttype: 'baseline' | 'diff' | 'result'\n\tbase64: string\n}\n","import React from 'react'\nimport { addons, types } from 'storybook/manager-api'\nimport { VisPanel } from './components/vis_panel.tsx'\nimport { NAME, VIS_PANEL_ID } from './shared/contants.ts'\nimport {\n\tIMAGE_SNAPSHOT_RESULTS_RESPONSE,\n\trequestImageSnapshotResults,\n\ttype ImageSnapshotResults,\n\ttype VisEvent,\n} from './shared/events.ts'\n\n// Register the addon\naddons.register(NAME, (api) => {\n\t// Register the tool\n\tif ((globalThis as any).CONFIG_TYPE === 'DEVELOPMENT') {\n\t\taddons.add(VIS_PANEL_ID, {\n\t\t\ttype: types.PANEL,\n\t\t\ttitle: 'Vis',\n\t\t\tmatch: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n\t\t\trender({ active }) {\n\t\t\t\tif (!active) return null\n\t\t\t\tconst storyData = api.getCurrentStoryData()\n\t\t\t\tif (!storyData) return null\n\t\t\t\tapi.emit(NAME, requestImageSnapshotResults(storyData))\n\t\t\t\tasync function getSnapshotResults() {\n\t\t\t\t\treturn new Promise<ImageSnapshotResults[]>((resolve) => {\n\t\t\t\t\t\tapi.once(NAME, (event: VisEvent) => {\n\t\t\t\t\t\t\tif (event.name !== storyData.name) return\n\t\t\t\t\t\t\tif (event.importPath !== storyData.importPath) return\n\t\t\t\t\t\t\tif (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) {\n\t\t\t\t\t\t\t\tresolve(event.results)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\t<VisPanel\n\t\t\t\t\t\tactive={active}\n\t\t\t\t\t\tgetSnapshotResults={getSnapshotResults}\n\t\t\t\t\t\tonRefresh={() => {\n\t\t\t\t\t\t\tif (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))\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"],"mappings":";;;;;;;;AAaA,MAAa,WAAW,KAAK,SAASA,WAAS,EAAE,QAAQ,oBAAoB,aAAyB;CACrG,MAAM,CAAC,iBAAiB,sBAAsB,SAAiC,EAAE,CAAC;AAElF,iBAAgB;AACf,sBAAoB,CAAC,KAAK,mBAAmB;IAC3C,CAAC,mBAAmB,CAAC;CAExB,MAAM,iBAAiB,gBAAgB,QACrC,KAAK,WAAW;EAEhB,MAAM,MAAM,IADM,OAAO,gBAAgB,MAAM,kBAAkB,SAAS,EAAE,CAClD,IAAI,OAAO;AACrC,MAAI,OAAO,CAAC,GAAI,IAAI,QAAQ,EAAE,EAAG,OAAO;AACxC,SAAO;IAER,EAAE,CACF;AACD,QACC,oCAAC,cAAmB,UAClB,gBAAgB,SAAS,IACzB,oCAAC,cAAW,kBACV,OAAO,QAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,aAC1C,oCAAC,SAAS,OACR,QAAQ,MAAM,WAAW,OAAO,SAAS,OAAO,GAChD,0DACC,oCAAC,eAAY,gBAAQ,IAAkB,EACtC,QAAQ,KAAK,WACb,oCAAC;EAAI,KAAK,OAAO;EAAU,KAAK,yBAAyB,OAAO;EAAU,KAAK,OAAO;GAAY,CACjG,CACA,GAEH,0DACC,oCAAC,mBACA,oCAAC,cAAM,IAAW,EAClB,oCAAC,cACA,eAAe;AACd,aAAW;AACX,sBAAoB,CAAC,KAAK,mBAAmB;MAG9C,oCAAC,kBAAc,CACH,CACA,EACd,oCAAC;EACA,KAAK,QAAQ,GAAG;EAChB,KAAK,yBAAyB,QAAQ,GAAG;EACzC,KAAK,QAAQ,GAAG;GACf,CACA,CAEC,CACL,CACU,GAEb,oCAAC,mBAAY,uCAAkD,CAEpD;EAEb;AAEF,MAAM,cAAc,OAAO,KAA2B,EAAE,OAAO,cAAc;CAC5E,SAAS;CACT,YAAY;CACZ,KAAK;CACL,cAAc;CACd,eAAe;CACf,iBAAiB,SAAS,MAAM,WAAW,WAAW,MAAM,WAAW;CACvE,OAAO,MAAM;CACb,EAAE;;;;AChFH,MAAa,OAAO;AACpB,MAAa,eAAe,GAAG,KAAK;;;;ACCpC,MAAa,iCAAiC;AAC9C,MAAa,kCAAkC;AAE/C,SAAgB,4BAA4B,EAAE,MAAM,cAAoD;AACvG,QAAO;EACN,MAAM;EACN;EACA;EACA;;;;;ACEF,OAAO,SAAS,OAAO,QAAQ;AAE9B,KAAK,WAAmB,gBAAgB,cACvC,QAAO,IAAI,cAAc;EACxB,MAAM,MAAM;EACZ,OAAO;EACP,QAAQ,EAAE,OAAO,eAAe,CAAC,SAAS,aAAa;EACvD,OAAO,EAAE,UAAU;AAClB,OAAI,CAAC,OAAQ,QAAO;GACpB,MAAM,YAAY,IAAI,qBAAqB;AAC3C,OAAI,CAAC,UAAW,QAAO;AACvB,OAAI,KAAK,MAAM,4BAA4B,UAAU,CAAC;GACtD,eAAe,qBAAqB;AACnC,WAAO,IAAI,SAAiC,YAAY;AACvD,SAAI,KAAK,OAAO,UAAoB;AACnC,UAAI,MAAM,SAAS,UAAU,KAAM;AACnC,UAAI,MAAM,eAAe,UAAU,WAAY;AAC/C,UAAI,MAAM,SAAS,gCAClB,SAAQ,MAAM,QAAQ;OAEtB;MACD;;AAEH,UACC,oCAAC;IACQ;IACY;IACpB,iBAAiB;AAChB,SAAI,UAAW,KAAI,KAAK,MAAM,4BAA4B,UAAU,CAAC;;KAErE;;EAGJ,CAAC;EAEF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vis_annotation-DqZTkmEN.js","names":["toMatchImageSnapshot"
|
|
1
|
+
{"version":3,"file":"vis_annotation-DqZTkmEN.js","names":["toMatchImageSnapshot"],"sources":["../src/client/page/to_match_image_snapshot.ts","../src/client/vitest_proxy.ts","../src/client/expect/to_match_image_snapshot.ts","../src/client/storybook/expect_extend.ts","../src/client/storybook/tags.ts","../src/preview/vis_annotation.ts"],"sourcesContent":["import {\n\ttype ComparisonMethod,\n\ttype ToMatchPageImageSnapshotOptions,\n\tmatchPageImageSnapshotAction,\n\ttoTaskId,\n} from 'vitest-plugin-vis/client-api'\nimport { commands, getCurrentTest } from '../vitest_proxy.ts'\n\nexport function toMatchImageSnapshot<M extends ComparisonMethod = 'pixel'>(\n\toptions?: ToMatchPageImageSnapshotOptions<M> | undefined,\n) {\n\tconst test = getCurrentTest()\n\n\t/* v8 ignore start: stub as success when not in a test (e.g. in a story) */\n\tif (!test) return Promise.resolve()\n\t/* v8 ignore end */\n\n\treturn matchPageImageSnapshotAction(commands, toTaskId(test), options)\n}\n","import type { SnapshotTestMeta } from 'vitest-plugin-vis/client-api'\nimport type { BrowserCommands, BrowserPage } from 'vitest/browser'\nimport { toMatchImageSnapshot } from './page/to_match_image_snapshot.ts'\n\nlet browserContext: Awaited<typeof import('vitest/browser')>\nlet vitestSuite: Awaited<typeof import('vitest/suite')>\n\nif ((globalThis as any).__vitest_browser__) {\n\timport('vitest/browser').then((m) => {\n\t\tm.page.extend({ toMatchImageSnapshot })\n\t\tbrowserContext = m\n\t})\n\timport('vitest/suite').then((m) => {\n\t\tvitestSuite = m\n\t})\n}\n\nexport const page = new Proxy<BrowserPage>({} as any, {\n\tget(_target, prop) {\n\t\tconst r = (browserContext?.page as any)?.[prop]\n\t\tif (prop === 'toMatchImageSnapshot' && r === undefined) {\n\t\t\treturn () => {}\n\t\t}\n\t\treturn r\n\t},\n})\n\nexport const commands = new Proxy<BrowserCommands>({} as any, {\n\tget(_target, prop) {\n\t\treturn (browserContext?.commands as any)?.[prop]\n\t},\n})\n\nexport const getCurrentTest = () =>\n\tvitestSuite?.getCurrentTest() as (ReturnType<typeof vitestSuite.getCurrentTest> & SnapshotTestMeta) | undefined\n","import type { AsyncExpectationResult } from '@vitest/expect'\nimport {\n\ttype ComparisonMethod,\n\ttype ToMatchImageSnapshotOptions,\n\tmatchImageSnapshotAction,\n\tsuccess,\n\ttoTaskId,\n} from 'vitest-plugin-vis/client-api'\nimport { commands, getCurrentTest } from '../vitest_proxy.ts'\n\nexport function toMatchImageSnapshot<M extends ComparisonMethod>(\n\t/**\n\t * The element or locator to take the snapshot of,\n\t * or the base64 value of the image to compare against.\n\t */\n\tsubject: any,\n\toptions?: ToMatchImageSnapshotOptions<M> | undefined,\n): AsyncExpectationResult {\n\tconst test = getCurrentTest()\n\n\t/* v8 ignore start: stub as success when not in a test (e.g. in a story) */\n\tif (!test) return Promise.resolve(success)\n\t/* v8 ignore end */\n\n\treturn matchImageSnapshotAction(commands, toTaskId(test), subject, options).then(() => success)\n}\n","import { expect } from 'storybook/test'\nimport { toMatchImageSnapshot } from '../expect/to_match_image_snapshot.ts'\n\nexpect.extend({ toMatchImageSnapshot })\n","export function isSnapshotEnabled(tags: string[]) {\n\tconst noSnapshotIndex = tags.lastIndexOf('!snapshot')\n\tconst snapshotIndex = tags.lastIndexOf('snapshot')\n\n\tif (noSnapshotIndex < 0 && snapshotIndex < 0) return false\n\n\treturn noSnapshotIndex < snapshotIndex\n}\n","import type { NamedOrDefaultProjectAnnotations } from 'storybook/internal/types'\nimport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nimport { isSnapshotEnabled } from '../client/storybook/tags.ts'\nimport { getCurrentTest } from '../client/vitest_proxy.ts'\n\nexport const visAnnotations = {\n\tbeforeEach(ctx) {\n\t\tconst test = getCurrentTest()\n\n\t\tsetAutoSnapshotOptions({\n\t\t\tenable: isSnapshotEnabled(ctx.tags),\n\t\t\t...ctx.parameters?.snapshot,\n\t\t\ttags: ctx.tags,\n\t\t\t...test?.meta.vis,\n\t\t})\n\t},\n} satisfies NamedOrDefaultProjectAnnotations<any>\n"],"mappings":";;;;;AAQA,SAAgBA,uBACf,SACC;CACD,MAAM,OAAO,gBAAgB;;AAG7B,KAAI,CAAC,KAAM,QAAO,QAAQ,SAAS;;AAGnC,QAAO,6BAA6B,UAAU,SAAS,KAAK,EAAE,QAAQ;;;;;ACbvE,IAAI;AACJ,IAAI;AAEJ,IAAK,WAAmB,oBAAoB;AAC3C,QAAO,kBAAkB,MAAM,MAAM;AACpC,IAAE,KAAK,OAAO,EAAE,8CAAsB,CAAC;AACvC,mBAAiB;GAChB;AACF,QAAO,gBAAgB,MAAM,MAAM;AAClC,gBAAc;GACb;;AAGH,MAAa,OAAO,IAAI,MAAmB,EAAE,EAAS,EACrD,IAAI,SAAS,MAAM;CAClB,MAAM,KAAK,gBAAgB,QAAe;AAC1C,KAAI,SAAS,0BAA0B,MAAM,OAC5C,cAAa;AAEd,QAAO;GAER,CAAC;AAEF,MAAa,WAAW,IAAI,MAAuB,EAAE,EAAS,EAC7D,IAAI,SAAS,MAAM;AAClB,SAAQ,gBAAgB,YAAmB;GAE5C,CAAC;AAEF,MAAa,uBACZ,aAAa,gBAAgB;;;;ACxB9B,SAAgB,qBAKf,SACA,SACyB;CACzB,MAAM,OAAO,gBAAgB;;AAG7B,KAAI,CAAC,KAAM,QAAO,QAAQ,QAAQ,QAAQ;;AAG1C,QAAO,yBAAyB,UAAU,SAAS,KAAK,EAAE,SAAS,QAAQ,CAAC,WAAW,QAAQ;;;;;ACrBhG,OAAO,OAAO,EAAE,sBAAsB,CAAC;;;;ACHvC,SAAgB,kBAAkB,MAAgB;CACjD,MAAM,kBAAkB,KAAK,YAAY,YAAY;CACrD,MAAM,gBAAgB,KAAK,YAAY,WAAW;AAElD,KAAI,kBAAkB,KAAK,gBAAgB,EAAG,QAAO;AAErD,QAAO,kBAAkB;;;;;ACD1B,MAAa,iBAAiB,EAC7B,WAAW,KAAK;CACf,MAAM,OAAO,gBAAgB;AAE7B,0BAAuB;EACtB,QAAQ,kBAAkB,IAAI,KAAK;EACnC,GAAG,IAAI,YAAY;EACnB,MAAM,IAAI;EACV,GAAG,MAAM,KAAK;EACd,CAAC;GAEH"}
|
package/dist/vitest-setup.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./global_matcher_augment-CYxLwns2.js";
|
|
2
2
|
import * as storybook_internal_csf1 from "storybook/internal/csf";
|
|
3
3
|
import { setAutoSnapshotOptions } from "vitest-plugin-vis";
|
|
4
|
-
import * as
|
|
4
|
+
import * as vitest_plugin_vis_setup_api0 from "vitest-plugin-vis/setup-api";
|
|
5
5
|
|
|
6
6
|
//#region src/preview/vis_annotation.d.ts
|
|
7
7
|
declare const visAnnotations: {
|
|
@@ -9,7 +9,7 @@ declare const visAnnotations: {
|
|
|
9
9
|
};
|
|
10
10
|
//#endregion
|
|
11
11
|
//#region src/vitest-setup.d.ts
|
|
12
|
-
declare const vis:
|
|
12
|
+
declare const vis: vitest_plugin_vis_setup_api0.VisClientConfigurator<{
|
|
13
13
|
tags: string[];
|
|
14
14
|
}>;
|
|
15
15
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest-setup.d.ts","names":[],"sources":["../src/preview/vis_annotation.ts","../src/vitest-setup.ts"],"sourcesContent":[],"mappings":";;;;;;cAKa;kBAWoC,uBAAA,CAAA,kBAAA,uBAAA,CAAA,IAAA;;;;cCTpC,KAA6C,
|
|
1
|
+
{"version":3,"file":"vitest-setup.d.ts","names":[],"sources":["../src/preview/vis_annotation.ts","../src/vitest-setup.ts"],"sourcesContent":[],"mappings":";;;;;;cAKa;kBAWoC,uBAAA,CAAA,kBAAA,uBAAA,CAAA,IAAA;;;;cCTpC,KAA6C,4BAAA,CAA1C"}
|
package/dist/vitest-setup.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as commands, t as visAnnotations } from "./vis_annotation-DqZTkmEN.js";
|
|
2
2
|
import { setAutoSnapshotOptions } from "vitest-plugin-vis";
|
|
3
|
-
import { createVis } from "vitest-plugin-vis/setup";
|
|
3
|
+
import { createVis } from "vitest-plugin-vis/setup-api";
|
|
4
4
|
|
|
5
5
|
//#region src/vitest-setup.ts
|
|
6
6
|
const vis = createVis(commands);
|
package/dist/vitest-setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest-setup.js","names":[],"sources":["../src/vitest-setup.ts"],"sourcesContent":["// `storybook-addon-vis/vitest-setup` provides code needed in `vitest.setup.ts`.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport { createVis } from 'vitest-plugin-vis/setup'\nimport { commands } from './client/vitest_proxy.ts'\n\nexport const vis = createVis<{ tags: string[] }>(commands)\nexport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nexport { visAnnotations } from './preview/vis_annotation.ts'\n"],"mappings":";;;;;AAOA,MAAa,MAAM,UAA8B,SAAS"}
|
|
1
|
+
{"version":3,"file":"vitest-setup.js","names":[],"sources":["../src/vitest-setup.ts"],"sourcesContent":["// `storybook-addon-vis/vitest-setup` provides code needed in `vitest.setup.ts`.\nimport './client/storybook/expect_extend.ts'\nimport './shared/global_matcher_augment.ts'\n\nimport { createVis } from 'vitest-plugin-vis/setup-api'\nimport { commands } from './client/vitest_proxy.ts'\n\nexport const vis = createVis<{ tags: string[] }>(commands)\nexport { setAutoSnapshotOptions } from 'vitest-plugin-vis'\nexport { visAnnotations } from './preview/vis_annotation.ts'\n"],"mappings":";;;;;AAOA,MAAa,MAAM,UAA8B,SAAS"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storybook-addon-vis",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "Storybook Vitest visual testing addon",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"image-snapshot",
|
|
@@ -66,12 +66,12 @@
|
|
|
66
66
|
"is-ci": "^4.1.0",
|
|
67
67
|
"memoize": "^10.1.0",
|
|
68
68
|
"pathe": "^2.0.3",
|
|
69
|
-
"type-plus": "8.0.0-beta.
|
|
70
|
-
"vitest-plugin-vis": "^4.
|
|
69
|
+
"type-plus": "8.0.0-beta.8",
|
|
70
|
+
"vitest-plugin-vis": "^4.2.0"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@repobuddy/storybook": "^2.1.2",
|
|
74
|
-
"@storybook-community/storybook-dark-mode": "^7.0
|
|
74
|
+
"@storybook-community/storybook-dark-mode": "^7.1.0",
|
|
75
75
|
"@storybook/addon-docs": "^10.1.10",
|
|
76
76
|
"@storybook/addon-vitest": "^10.1.10",
|
|
77
77
|
"@storybook/react-vite": "^10.1.10",
|
|
@@ -80,12 +80,12 @@
|
|
|
80
80
|
"@testing-library/react": "^16.0.1",
|
|
81
81
|
"@types/react": "^19.2.2",
|
|
82
82
|
"@types/react-dom": "^19.2.1",
|
|
83
|
-
"@vitejs/plugin-react": "^5.1.
|
|
84
|
-
"@vitest/browser": "^4.0.
|
|
85
|
-
"@vitest/browser-playwright": "^4.0.
|
|
86
|
-
"@vitest/browser-webdriverio": "^4.0.
|
|
87
|
-
"@vitest/coverage-istanbul": "^4.0.
|
|
88
|
-
"@vitest/expect": "^4.0.
|
|
83
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
84
|
+
"@vitest/browser": "^4.0.16",
|
|
85
|
+
"@vitest/browser-playwright": "^4.0.16",
|
|
86
|
+
"@vitest/browser-webdriverio": "^4.0.16",
|
|
87
|
+
"@vitest/coverage-istanbul": "^4.0.16",
|
|
88
|
+
"@vitest/expect": "^4.0.16",
|
|
89
89
|
"boxen": "^8.0.1",
|
|
90
90
|
"cross-env": "^10.0.0",
|
|
91
91
|
"dedent": "^1.5.1",
|
|
@@ -96,10 +96,10 @@
|
|
|
96
96
|
"storybook": "^10.1.10",
|
|
97
97
|
"storybook-addon-tag-badges": "^3.0.2",
|
|
98
98
|
"tailwindcss": "^4.1.14",
|
|
99
|
-
"tsdown": "^0.
|
|
99
|
+
"tsdown": "^0.19.0",
|
|
100
100
|
"typescript": "^5.9.3",
|
|
101
|
-
"vite": "^7.
|
|
102
|
-
"vitest": "^4.0.
|
|
101
|
+
"vite": "^7.3.0",
|
|
102
|
+
"vitest": "^4.0.16",
|
|
103
103
|
"vitest-browser-react": "^2.0.2",
|
|
104
104
|
"webdriverio": "latest",
|
|
105
105
|
"zx": "^8.0.0"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RefreshIcon } from '@storybook/icons'
|
|
2
|
-
import React, { memo } from 'react'
|
|
2
|
+
import React, { memo, useEffect, useState } from 'react'
|
|
3
3
|
import { AddonPanel, IconButton, Placeholder, ScrollArea } from 'storybook/internal/components'
|
|
4
4
|
import { styled } from 'storybook/theming'
|
|
5
5
|
import { SNAPSHOT_ROOT_DIR } from 'vitest-plugin-vis/client-api'
|
|
@@ -7,11 +7,17 @@ import type { ImageSnapshotResults } from '../shared/events.ts'
|
|
|
7
7
|
|
|
8
8
|
interface PanelProps {
|
|
9
9
|
active: boolean
|
|
10
|
-
|
|
10
|
+
getSnapshotResults: () => Promise<ImageSnapshotResults[]>
|
|
11
11
|
onRefresh: () => void
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export const VisPanel = memo(function VisPanel({ active,
|
|
14
|
+
export const VisPanel = memo(function VisPanel({ active, getSnapshotResults, onRefresh }: PanelProps) {
|
|
15
|
+
const [snapshotResults, setSnapshotResults] = useState<ImageSnapshotResults[]>([])
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
getSnapshotResults().then(setSnapshotResults)
|
|
19
|
+
}, [getSnapshotResults])
|
|
20
|
+
|
|
15
21
|
const groupedResults = snapshotResults.reduce(
|
|
16
22
|
(acc, result) => {
|
|
17
23
|
const suiteName = result.snapshotRootDir.slice(SNAPSHOT_ROOT_DIR.length + 1)
|
|
@@ -38,7 +44,12 @@ export const VisPanel = memo(function VisPanel({ active, snapshotResults = [], o
|
|
|
38
44
|
<>
|
|
39
45
|
<SnapshotRow>
|
|
40
46
|
<span>{key}</span>
|
|
41
|
-
<IconButton
|
|
47
|
+
<IconButton
|
|
48
|
+
onClick={() => {
|
|
49
|
+
onRefresh()
|
|
50
|
+
getSnapshotResults().then(setSnapshotResults)
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
42
53
|
<RefreshIcon />
|
|
43
54
|
</IconButton>
|
|
44
55
|
</SnapshotRow>
|
package/src/manager.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react'
|
|
2
2
|
import { addons, types } from 'storybook/manager-api'
|
|
3
3
|
import { VisPanel } from './components/vis_panel.tsx'
|
|
4
4
|
import { NAME, VIS_PANEL_ID } from './shared/contants.ts'
|
|
@@ -18,37 +18,25 @@ addons.register(NAME, (api) => {
|
|
|
18
18
|
title: 'Vis',
|
|
19
19
|
match: ({ tabId, viewMode }) => !tabId && viewMode === 'story',
|
|
20
20
|
render({ active }) {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if (!active) return null
|
|
23
22
|
const storyData = api.getCurrentStoryData()
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
if (!storyData) return null
|
|
24
|
+
api.emit(NAME, requestImageSnapshotResults(storyData))
|
|
25
|
+
async function getSnapshotResults() {
|
|
26
|
+
return new Promise<ImageSnapshotResults[]>((resolve) => {
|
|
27
|
+
api.once(NAME, (event: VisEvent) => {
|
|
28
28
|
if (event.name !== storyData.name) return
|
|
29
29
|
if (event.importPath !== storyData.importPath) return
|
|
30
|
-
|
|
31
30
|
if (event.type === IMAGE_SNAPSHOT_RESULTS_RESPONSE) {
|
|
32
|
-
|
|
31
|
+
resolve(event.results)
|
|
33
32
|
}
|
|
34
|
-
}),
|
|
35
|
-
// api.on('UNIVERSAL_STORE:storybook/test', (event) => {
|
|
36
|
-
// console.log('storybook/test', event)
|
|
37
|
-
// }),
|
|
38
|
-
]
|
|
39
|
-
if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))
|
|
40
|
-
return () =>
|
|
41
|
-
disposes.forEach((dispose) => {
|
|
42
|
-
dispose()
|
|
43
33
|
})
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!active) return null
|
|
47
|
-
|
|
34
|
+
})
|
|
35
|
+
}
|
|
48
36
|
return (
|
|
49
37
|
<VisPanel
|
|
50
38
|
active={active}
|
|
51
|
-
|
|
39
|
+
getSnapshotResults={getSnapshotResults}
|
|
52
40
|
onRefresh={() => {
|
|
53
41
|
if (storyData) api.emit(NAME, requestImageSnapshotResults(storyData))
|
|
54
42
|
}}
|
package/src/vitest-setup.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import './client/storybook/expect_extend.ts'
|
|
3
3
|
import './shared/global_matcher_augment.ts'
|
|
4
4
|
|
|
5
|
-
import { createVis } from 'vitest-plugin-vis/setup'
|
|
5
|
+
import { createVis } from 'vitest-plugin-vis/setup-api'
|
|
6
6
|
import { commands } from './client/vitest_proxy.ts'
|
|
7
7
|
|
|
8
8
|
export const vis = createVis<{ tags: string[] }>(commands)
|