@argos-ci/storybook 2.1.6 → 2.1.7

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.
@@ -0,0 +1,5 @@
1
+ const argosScreenshot = async (...args) => {
2
+ const { argosScreenshot } = await import("./test-runner.js");
3
+ return argosScreenshot(...args);
4
+ };
5
+ exports.argosScreenshot = argosScreenshot;
@@ -0,0 +1,54 @@
1
+ import { TestContext } from '@storybook/test-runner';
2
+ import { ArgosScreenshotOptions as ArgosScreenshotOptions$1 } from '@argos-ci/playwright';
3
+ import { Page } from 'playwright';
4
+
5
+ type StorybookGlobals = Record<string, any>;
6
+ type FitToContent = {
7
+ /**
8
+ * Padding around the content in pixels.
9
+ * @default 16
10
+ */
11
+ padding: number;
12
+ /**
13
+ * Zoom level for the content.
14
+ * @default 2
15
+ */
16
+ zoom: number;
17
+ };
18
+ /**
19
+ * Argos parameters in Storybook.
20
+ */
21
+ interface ArgosStorybookParameters {
22
+ /**
23
+ * Modes for the story.
24
+ */
25
+ modes?: Record<string, StorybookGlobals>;
26
+ /**
27
+ * Fit to content option for the story.
28
+ */
29
+ fitToContent?: boolean | Partial<FitToContent>;
30
+ }
31
+
32
+ type ArgosScreenshotOptions = Omit<ArgosScreenshotOptions$1, "viewports">;
33
+
34
+ /**
35
+ * Stabilize the UI and takes a screenshot of the application under test.
36
+ *
37
+ * @example argosScreenshot(page, context, options)
38
+ * @see https://argos-ci.com/docs/playwright#api-overview
39
+ */
40
+ declare function argosScreenshot(
41
+ /**
42
+ * Playwright `page` object.
43
+ */
44
+ page: Page,
45
+ /**
46
+ * Context of the test.
47
+ */
48
+ context: TestContext,
49
+ /**
50
+ * Options for the screenshot.
51
+ */
52
+ options?: ArgosScreenshotOptions): Promise<void>;
53
+
54
+ export { type ArgosScreenshotOptions, type ArgosStorybookParameters, argosScreenshot };
@@ -0,0 +1,214 @@
1
+ // src/test-runner.ts
2
+ import { getStoryContext, waitForPageReady } from "@storybook/test-runner";
3
+
4
+ // src/utils/screenshot.ts
5
+ import {
6
+ argosScreenshot as argosPlaywrightScreenshot,
7
+ DO_NOT_USE_setMetadataConfig
8
+ } from "@argos-ci/playwright";
9
+
10
+ // src/utils/metadata.ts
11
+ import { readVersionFromPackage } from "@argos-ci/util";
12
+ import { createRequire } from "node:module";
13
+ var require2 = createRequire(import.meta.url);
14
+ async function getArgosStorybookVersion() {
15
+ const pkgPath = require2.resolve("@argos-ci/storybook/package.json");
16
+ return readVersionFromPackage(pkgPath);
17
+ }
18
+
19
+ // src/utils/parameters.ts
20
+ function getDefaultViewport(parameters) {
21
+ const defaultViewport = parameters?.viewport?.defaultViewport;
22
+ if (defaultViewport) {
23
+ return getViewport(parameters, defaultViewport);
24
+ }
25
+ return null;
26
+ }
27
+ function getViewport(parameters, viewportName) {
28
+ if (typeof viewportName === "number") {
29
+ return { width: viewportName, height: 720 };
30
+ }
31
+ const viewports = parameters?.viewport?.viewports;
32
+ if (viewports && viewportName in viewports) {
33
+ if ("styles" in viewports[viewportName] && viewports[viewportName].styles) {
34
+ const width = parseInt(viewports[viewportName].styles.width, 10);
35
+ const height = parseInt(viewports[viewportName].styles.height, 10);
36
+ if (!isNaN(width) && !isNaN(height)) {
37
+ return { width, height };
38
+ }
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ function getArgosParameters(parameters) {
44
+ if ("argos" in parameters && parameters.argos && typeof parameters.argos === "object") {
45
+ return parameters.argos;
46
+ }
47
+ if ("chromatic" in parameters && parameters.chromatic && typeof parameters.chromatic === "object") {
48
+ return parameters.chromatic;
49
+ }
50
+ return null;
51
+ }
52
+ var DEFAULT_FIT_TO_CONTENT = {
53
+ padding: 16,
54
+ zoom: 2
55
+ };
56
+ function getFitToContentFromParameters(parameters) {
57
+ const argosParameters = getArgosParameters(parameters);
58
+ if (argosParameters && "fitToContent" in argosParameters) {
59
+ if (typeof argosParameters.fitToContent === "boolean") {
60
+ return argosParameters.fitToContent ? DEFAULT_FIT_TO_CONTENT : null;
61
+ }
62
+ if (typeof argosParameters.fitToContent === "object" && argosParameters.fitToContent) {
63
+ return {
64
+ ...DEFAULT_FIT_TO_CONTENT,
65
+ ...argosParameters.fitToContent
66
+ };
67
+ }
68
+ }
69
+ return DEFAULT_FIT_TO_CONTENT;
70
+ }
71
+
72
+ // src/utils/screenshot.ts
73
+ async function storybookArgosScreenshot(page, context, options) {
74
+ const argosOptions = {
75
+ ...options,
76
+ // Disable aria-busy stabilization by default
77
+ stabilize: options?.stabilize ?? {
78
+ waitForAriaBusy: false,
79
+ ...typeof options?.stabilize === "object" ? options.stabilize : {}
80
+ }
81
+ };
82
+ const version = await getArgosStorybookVersion();
83
+ const storyUrl = `http://localhost:6006/?path=/story/${context.story.id}`;
84
+ DO_NOT_USE_setMetadataConfig({
85
+ sdk: { name: "@argos-ci/storybook", version },
86
+ playwrightLibraries: context.playwrightLibraries,
87
+ url: storyUrl,
88
+ test: context.test
89
+ });
90
+ const argosParameters = getArgosParameters(context.story.parameters);
91
+ const modes = argosParameters?.modes;
92
+ const allAttachments = [];
93
+ if (modes) {
94
+ for (const [name, globals] of Object.entries(modes)) {
95
+ if (globals.disabled) {
96
+ continue;
97
+ }
98
+ const attachments = await runHooksAndScreenshot({
99
+ page,
100
+ context,
101
+ options: argosOptions,
102
+ suffix: ` ${name}`,
103
+ globals: {
104
+ ...context.story.globals,
105
+ ...globals
106
+ }
107
+ });
108
+ allAttachments.push(...attachments);
109
+ }
110
+ } else {
111
+ const attachments = await runHooksAndScreenshot({
112
+ page,
113
+ context,
114
+ options: argosOptions,
115
+ globals: context.story.globals ?? {}
116
+ });
117
+ allAttachments.push(...attachments);
118
+ }
119
+ await context.setViewportSize("default");
120
+ if (context.applyGlobals) {
121
+ await context.applyGlobals({
122
+ handler: page,
123
+ globals: {}
124
+ });
125
+ }
126
+ await setStorybookGlobals({ page, globals: {} });
127
+ return allAttachments;
128
+ }
129
+ async function setStorybookGlobals(args) {
130
+ const { page, globals } = args;
131
+ await page.evaluate((globals2) => {
132
+ const channel = (() => {
133
+ if ("__STORYBOOK_PREVIEW__" in globalThis) {
134
+ return globalThis.__STORYBOOK_PREVIEW__.channel;
135
+ }
136
+ if ("__STORYBOOK_ADDONS_CHANNEL__" in globalThis) {
137
+ return globalThis.__STORYBOOK_ADDONS_CHANNEL__;
138
+ }
139
+ return null;
140
+ })();
141
+ if (!channel) {
142
+ throw new Error(
143
+ "@argos-ci/storybook: Unable to find Storybook preview instance."
144
+ );
145
+ }
146
+ const initialGlobals = channel.last("globalsUpdated")?.[0].initialGlobals;
147
+ channel.emit("updateGlobals", {
148
+ globals: { ...initialGlobals, ...globals2 }
149
+ });
150
+ }, globals);
151
+ }
152
+ async function runHooksAndScreenshot(args) {
153
+ const { page, context, options, globals } = args;
154
+ if (context.applyGlobals) {
155
+ await context.applyGlobals({
156
+ handler: page,
157
+ globals
158
+ });
159
+ }
160
+ await setStorybookGlobals({ page, globals });
161
+ const viewportFromGlobals = globals.viewport ? getViewport(context.story.parameters, globals.viewport) : null;
162
+ const viewport = viewportFromGlobals ?? getDefaultViewport(context.story.parameters) ?? "default";
163
+ await context.setViewportSize(viewport);
164
+ return argosPlaywrightScreenshot(
165
+ page,
166
+ context.name + (args.suffix ?? ""),
167
+ options
168
+ );
169
+ }
170
+
171
+ // src/test-runner.ts
172
+ import { join } from "node:path";
173
+ async function argosScreenshot(page, context, options) {
174
+ const storyContext = await getStoryContext(page, context);
175
+ const fitToContent = getFitToContentFromParameters(storyContext.parameters);
176
+ await storybookArgosScreenshot(
177
+ page,
178
+ {
179
+ name: join(context.title, context.name),
180
+ playwrightLibraries: ["@storybook/test-runner"],
181
+ applyGlobals: async ({ handler }) => {
182
+ await waitForPageReady(handler);
183
+ },
184
+ story: {
185
+ id: storyContext.id,
186
+ parameters: storyContext.parameters,
187
+ // We don't have access to globals in this context.
188
+ globals: null
189
+ },
190
+ setViewportSize: async (size) => {
191
+ if (size === "default") {
192
+ await page.setViewportSize({ width: 1280, height: 720 });
193
+ } else {
194
+ await page.setViewportSize(size);
195
+ }
196
+ }
197
+ },
198
+ applyFitToContent(options, fitToContent)
199
+ );
200
+ }
201
+ function applyFitToContent(options, fitToContent) {
202
+ if (!fitToContent) {
203
+ return options;
204
+ }
205
+ const { padding, zoom } = fitToContent;
206
+ return {
207
+ ...options,
208
+ element: "#storybook-root",
209
+ argosCSS: `#storybook-root { padding: ${padding}px; width: fit-content; height: fit-content; zoom: ${zoom}; }` + (options?.argosCSS ?? "")
210
+ };
211
+ }
212
+ export {
213
+ argosScreenshot
214
+ };
@@ -0,0 +1,60 @@
1
+ import { Plugin } from 'vitest/config';
2
+ import { BrowserCommand } from 'vitest/node';
3
+ import { ArgosScreenshotOptions as ArgosScreenshotOptions$1, MetadataConfig } from '@argos-ci/playwright';
4
+ import { Page, Frame, ViewportSize } from 'playwright';
5
+ import { UploadParameters } from '@argos-ci/core';
6
+
7
+ type StorybookGlobals = Record<string, any>;
8
+
9
+ type StorybookScreenshotContext<Handler extends Page | Frame> = {
10
+ name: string;
11
+ playwrightLibraries: string[];
12
+ test?: MetadataConfig["test"];
13
+ setViewportSize: (size: ViewportSize | "default") => Promise<void>;
14
+ /**
15
+ * Opportunity to apply globals or other context-specific settings.
16
+ * This can be useful to emulate dark mode or other visual modes.
17
+ * @example
18
+ * ```typescript
19
+ * applyGlobals: async ({ frame, globals }) => {
20
+ * await frame.evaluate((globals) => {
21
+ * if (globals.theme === "dark") {
22
+ * document.documentElement.classList.add("dark");
23
+ * } else {
24
+ * document.documentElement.classList.remove("dark");
25
+ * }
26
+ * }, globals);
27
+ * }
28
+ * ```
29
+ */
30
+ applyGlobals?: (input: {
31
+ handler: Handler;
32
+ globals: StorybookGlobals;
33
+ }) => Promise<void>;
34
+ story: {
35
+ id: string;
36
+ parameters: Record<string, any>;
37
+ globals: StorybookGlobals | null;
38
+ };
39
+ };
40
+ type ArgosScreenshotOptions = Omit<ArgosScreenshotOptions$1, "viewports">;
41
+
42
+ type ArgosReporterConfig = UploadParameters;
43
+
44
+ type ArgosScreenshotCommandArgs = [
45
+ Pick<StorybookScreenshotContext<Frame>, "name" | "story" | "test">
46
+ ];
47
+ interface ArgosVitestPluginOptions extends Pick<StorybookScreenshotContext<Frame>, "applyGlobals">, ArgosReporterConfig, ArgosScreenshotOptions {
48
+ /**
49
+ * Upload the report to Argos.
50
+ * @default true
51
+ */
52
+ uploadToArgos?: boolean;
53
+ }
54
+ /**
55
+ * Create a command for taking Argos screenshots in Vitest.
56
+ */
57
+ declare const createArgosScreenshotCommand: (pluginOptions?: ArgosVitestPluginOptions) => BrowserCommand<ArgosScreenshotCommandArgs>;
58
+ declare function argosVitestPlugin(options?: ArgosVitestPluginOptions): Plugin;
59
+
60
+ export { type ArgosScreenshotCommandArgs, type ArgosScreenshotOptions, type ArgosVitestPluginOptions, argosVitestPlugin, createArgosScreenshotCommand };
@@ -0,0 +1,307 @@
1
+ // src/utils/screenshot.ts
2
+ import {
3
+ argosScreenshot as argosPlaywrightScreenshot,
4
+ DO_NOT_USE_setMetadataConfig
5
+ } from "@argos-ci/playwright";
6
+
7
+ // src/utils/metadata.ts
8
+ import { readVersionFromPackage } from "@argos-ci/util";
9
+ import { createRequire } from "node:module";
10
+ var require2 = createRequire(import.meta.url);
11
+ async function getArgosStorybookVersion() {
12
+ const pkgPath = require2.resolve("@argos-ci/storybook/package.json");
13
+ return readVersionFromPackage(pkgPath);
14
+ }
15
+
16
+ // src/utils/parameters.ts
17
+ function getDefaultViewport(parameters) {
18
+ const defaultViewport = parameters?.viewport?.defaultViewport;
19
+ if (defaultViewport) {
20
+ return getViewport(parameters, defaultViewport);
21
+ }
22
+ return null;
23
+ }
24
+ function getViewport(parameters, viewportName) {
25
+ if (typeof viewportName === "number") {
26
+ return { width: viewportName, height: 720 };
27
+ }
28
+ const viewports = parameters?.viewport?.viewports;
29
+ if (viewports && viewportName in viewports) {
30
+ if ("styles" in viewports[viewportName] && viewports[viewportName].styles) {
31
+ const width = parseInt(viewports[viewportName].styles.width, 10);
32
+ const height = parseInt(viewports[viewportName].styles.height, 10);
33
+ if (!isNaN(width) && !isNaN(height)) {
34
+ return { width, height };
35
+ }
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+ function getArgosParameters(parameters) {
41
+ if ("argos" in parameters && parameters.argos && typeof parameters.argos === "object") {
42
+ return parameters.argos;
43
+ }
44
+ if ("chromatic" in parameters && parameters.chromatic && typeof parameters.chromatic === "object") {
45
+ return parameters.chromatic;
46
+ }
47
+ return null;
48
+ }
49
+ var DEFAULT_FIT_TO_CONTENT = {
50
+ padding: 16,
51
+ zoom: 2
52
+ };
53
+ function getFitToContentFromParameters(parameters) {
54
+ const argosParameters = getArgosParameters(parameters);
55
+ if (argosParameters && "fitToContent" in argosParameters) {
56
+ if (typeof argosParameters.fitToContent === "boolean") {
57
+ return argosParameters.fitToContent ? DEFAULT_FIT_TO_CONTENT : null;
58
+ }
59
+ if (typeof argosParameters.fitToContent === "object" && argosParameters.fitToContent) {
60
+ return {
61
+ ...DEFAULT_FIT_TO_CONTENT,
62
+ ...argosParameters.fitToContent
63
+ };
64
+ }
65
+ }
66
+ return DEFAULT_FIT_TO_CONTENT;
67
+ }
68
+
69
+ // src/utils/screenshot.ts
70
+ async function storybookArgosScreenshot(page, context, options) {
71
+ const argosOptions = {
72
+ ...options,
73
+ // Disable aria-busy stabilization by default
74
+ stabilize: options?.stabilize ?? {
75
+ waitForAriaBusy: false,
76
+ ...typeof options?.stabilize === "object" ? options.stabilize : {}
77
+ }
78
+ };
79
+ const version = await getArgosStorybookVersion();
80
+ const storyUrl = `http://localhost:6006/?path=/story/${context.story.id}`;
81
+ DO_NOT_USE_setMetadataConfig({
82
+ sdk: { name: "@argos-ci/storybook", version },
83
+ playwrightLibraries: context.playwrightLibraries,
84
+ url: storyUrl,
85
+ test: context.test
86
+ });
87
+ const argosParameters = getArgosParameters(context.story.parameters);
88
+ const modes = argosParameters?.modes;
89
+ const allAttachments = [];
90
+ if (modes) {
91
+ for (const [name, globals] of Object.entries(modes)) {
92
+ if (globals.disabled) {
93
+ continue;
94
+ }
95
+ const attachments = await runHooksAndScreenshot({
96
+ page,
97
+ context,
98
+ options: argosOptions,
99
+ suffix: ` ${name}`,
100
+ globals: {
101
+ ...context.story.globals,
102
+ ...globals
103
+ }
104
+ });
105
+ allAttachments.push(...attachments);
106
+ }
107
+ } else {
108
+ const attachments = await runHooksAndScreenshot({
109
+ page,
110
+ context,
111
+ options: argosOptions,
112
+ globals: context.story.globals ?? {}
113
+ });
114
+ allAttachments.push(...attachments);
115
+ }
116
+ await context.setViewportSize("default");
117
+ if (context.applyGlobals) {
118
+ await context.applyGlobals({
119
+ handler: page,
120
+ globals: {}
121
+ });
122
+ }
123
+ await setStorybookGlobals({ page, globals: {} });
124
+ return allAttachments;
125
+ }
126
+ async function setStorybookGlobals(args) {
127
+ const { page, globals } = args;
128
+ await page.evaluate((globals2) => {
129
+ const channel = (() => {
130
+ if ("__STORYBOOK_PREVIEW__" in globalThis) {
131
+ return globalThis.__STORYBOOK_PREVIEW__.channel;
132
+ }
133
+ if ("__STORYBOOK_ADDONS_CHANNEL__" in globalThis) {
134
+ return globalThis.__STORYBOOK_ADDONS_CHANNEL__;
135
+ }
136
+ return null;
137
+ })();
138
+ if (!channel) {
139
+ throw new Error(
140
+ "@argos-ci/storybook: Unable to find Storybook preview instance."
141
+ );
142
+ }
143
+ const initialGlobals = channel.last("globalsUpdated")?.[0].initialGlobals;
144
+ channel.emit("updateGlobals", {
145
+ globals: { ...initialGlobals, ...globals2 }
146
+ });
147
+ }, globals);
148
+ }
149
+ async function runHooksAndScreenshot(args) {
150
+ const { page, context, options, globals } = args;
151
+ if (context.applyGlobals) {
152
+ await context.applyGlobals({
153
+ handler: page,
154
+ globals
155
+ });
156
+ }
157
+ await setStorybookGlobals({ page, globals });
158
+ const viewportFromGlobals = globals.viewport ? getViewport(context.story.parameters, globals.viewport) : null;
159
+ const viewport = viewportFromGlobals ?? getDefaultViewport(context.story.parameters) ?? "default";
160
+ await context.setViewportSize(viewport);
161
+ return argosPlaywrightScreenshot(
162
+ page,
163
+ context.name + (args.suffix ?? ""),
164
+ options
165
+ );
166
+ }
167
+
168
+ // src/vitest-reporter.ts
169
+ import { upload } from "@argos-ci/core";
170
+ var ArgosReporter = class {
171
+ ctx;
172
+ config;
173
+ constructor(config) {
174
+ this.config = config;
175
+ }
176
+ onInit(ctx) {
177
+ this.ctx = ctx;
178
+ }
179
+ async onFinished() {
180
+ if (this.ctx.config.watch) {
181
+ return;
182
+ }
183
+ const res = await upload(this.config);
184
+ console.log(`\u2705 Argos build created: ${res.build.url}`);
185
+ }
186
+ };
187
+
188
+ // src/vitest-plugin.ts
189
+ import { resolve } from "node:path";
190
+ var createArgosScreenshotCommand = (pluginOptions) => {
191
+ const { applyGlobals, ...screenshotOptions } = pluginOptions ?? {};
192
+ return async (ctx, testContext) => {
193
+ const frame = await ctx.frame();
194
+ const fitToContent = getFitToContentFromParameters(
195
+ testContext.story.parameters
196
+ );
197
+ const after = await before(ctx);
198
+ const attachments = await storybookArgosScreenshot(
199
+ frame,
200
+ {
201
+ ...testContext,
202
+ playwrightLibraries: ["@storybook/addon-vitest"],
203
+ setViewportSize: async (size) => {
204
+ await ctx.page.evaluate((size2) => {
205
+ const iframe = document.querySelector('iframe[data-vitest="true"]');
206
+ if (!(iframe instanceof HTMLIFrameElement)) {
207
+ throw new Error("Vitest iframe not found");
208
+ }
209
+ if (size2 === "default") {
210
+ if (iframe.dataset.defaultWidth && iframe.dataset.defaultHeight) {
211
+ iframe.style.width = iframe.dataset.defaultWidth;
212
+ iframe.style.height = iframe.dataset.defaultHeight;
213
+ }
214
+ } else {
215
+ if (!iframe.dataset.defaultWidth && !iframe.dataset.defaultHeight) {
216
+ iframe.dataset.defaultWidth = iframe.style.width;
217
+ iframe.dataset.defaultHeight = iframe.style.height;
218
+ }
219
+ iframe.style.width = `${size2.width}px`;
220
+ iframe.style.height = `${size2.height}px`;
221
+ }
222
+ }, size);
223
+ },
224
+ applyGlobals
225
+ },
226
+ applyFitToContent(screenshotOptions, fitToContent)
227
+ );
228
+ await after();
229
+ return attachments;
230
+ };
231
+ };
232
+ async function before(ctx) {
233
+ await ctx.page.evaluate(() => {
234
+ const tester = document.getElementById("vitest-tester");
235
+ if (!(tester instanceof HTMLElement)) {
236
+ return;
237
+ }
238
+ const scale = tester.getAttribute("data-scale");
239
+ if (!scale) {
240
+ throw new Error("Vitest iframe data-scale attribute not found");
241
+ }
242
+ tester.dataset.bckTransform = tester.style.transform;
243
+ tester.style.transform = `scale(1)`;
244
+ });
245
+ return async () => {
246
+ await ctx.page.evaluate(() => {
247
+ const tester = document.getElementById("vitest-tester");
248
+ if (!(tester instanceof HTMLElement)) {
249
+ return;
250
+ }
251
+ tester.style.transform = tester.dataset.bckTransform ?? "";
252
+ });
253
+ };
254
+ }
255
+ function applyFitToContent(options, fitToContent) {
256
+ if (!fitToContent) {
257
+ return options;
258
+ }
259
+ const { padding, zoom } = fitToContent;
260
+ return {
261
+ ...options,
262
+ element: "body > div:not(.sb-wrapper)",
263
+ argosCSS: `body > div:not(.sb-wrapper) { padding: ${padding}px; width: fit-content; height: fit-content; zoom: ${zoom}; }` + (options?.argosCSS ?? "")
264
+ };
265
+ }
266
+ var cwd = process.cwd();
267
+ function argosVitestPlugin(options) {
268
+ const {
269
+ root: unresolvedRoot = "./screenshots",
270
+ uploadToArgos,
271
+ ...otherOptions
272
+ } = options ?? {};
273
+ const root = resolve(cwd, unresolvedRoot);
274
+ const setupFile = resolve(import.meta.dirname, "./vitest-setup-file.js");
275
+ return {
276
+ name: "@argos-ci/storybook/vitest-plugin",
277
+ configureVitest({ vitest, project }) {
278
+ project.config.setupFiles.push(setupFile);
279
+ if (uploadToArgos) {
280
+ vitest.config.reporters.push(
281
+ new ArgosReporter({ ...otherOptions, root })
282
+ );
283
+ }
284
+ },
285
+ config() {
286
+ return {
287
+ optimizeDeps: {
288
+ include: ["@argos-ci/storybook/internal/vitest-setup-file"]
289
+ },
290
+ test: {
291
+ browser: {
292
+ commands: {
293
+ argosScreenshot: createArgosScreenshotCommand({
294
+ ...otherOptions,
295
+ root
296
+ })
297
+ }
298
+ }
299
+ }
300
+ };
301
+ }
302
+ };
303
+ }
304
+ export {
305
+ argosVitestPlugin,
306
+ createArgosScreenshotCommand
307
+ };
@@ -0,0 +1,34 @@
1
+ // src/vitest.ts
2
+ import { afterEach } from "vitest";
3
+ import { server } from "@vitest/browser/context";
4
+ function setupArgos() {
5
+ afterEach(async (ctx) => {
6
+ const story = "story" in ctx ? ctx.story : null;
7
+ if (!story) {
8
+ throw new Error(
9
+ `@argos-ci/storybook/vitest-plugin should be used with @storybook/addon-vitest/vitest-plugin`
10
+ );
11
+ }
12
+ await server.commands.argosScreenshot({
13
+ name: story.id,
14
+ story: {
15
+ id: story.id,
16
+ parameters: story.parameters,
17
+ globals: story.globals
18
+ },
19
+ test: {
20
+ id: ctx.task.id,
21
+ title: ctx.task.name,
22
+ titlePath: [ctx.task.file.name, ctx.task.name],
23
+ location: {
24
+ line: ctx.task.location?.line ?? 1,
25
+ column: ctx.task.location?.column ?? 1,
26
+ file: ctx.task.file.filepath
27
+ }
28
+ }
29
+ });
30
+ });
31
+ }
32
+
33
+ // src/vitest-setup-file.ts
34
+ setupArgos();
@@ -0,0 +1,61 @@
1
+ import { MetadataConfig, ArgosScreenshotOptions as ArgosScreenshotOptions$1, Attachment } from '@argos-ci/playwright';
2
+ import { Page, Frame, ViewportSize } from 'playwright';
3
+
4
+ type StorybookGlobals = Record<string, any>;
5
+
6
+ type StorybookScreenshotContext<Handler extends Page | Frame> = {
7
+ name: string;
8
+ playwrightLibraries: string[];
9
+ test?: MetadataConfig["test"];
10
+ setViewportSize: (size: ViewportSize | "default") => Promise<void>;
11
+ /**
12
+ * Opportunity to apply globals or other context-specific settings.
13
+ * This can be useful to emulate dark mode or other visual modes.
14
+ * @example
15
+ * ```typescript
16
+ * applyGlobals: async ({ frame, globals }) => {
17
+ * await frame.evaluate((globals) => {
18
+ * if (globals.theme === "dark") {
19
+ * document.documentElement.classList.add("dark");
20
+ * } else {
21
+ * document.documentElement.classList.remove("dark");
22
+ * }
23
+ * }, globals);
24
+ * }
25
+ * ```
26
+ */
27
+ applyGlobals?: (input: {
28
+ handler: Handler;
29
+ globals: StorybookGlobals;
30
+ }) => Promise<void>;
31
+ story: {
32
+ id: string;
33
+ parameters: Record<string, any>;
34
+ globals: StorybookGlobals | null;
35
+ };
36
+ };
37
+ type ArgosScreenshotOptions = Omit<ArgosScreenshotOptions$1, "viewports">;
38
+
39
+ type ArgosScreenshotCommandArgs = [
40
+ Pick<StorybookScreenshotContext<Frame>, "name" | "story" | "test">
41
+ ];
42
+
43
+ declare module "@vitest/browser/context" {
44
+ interface BrowserCommands {
45
+ argosScreenshot: (...args: ArgosScreenshotCommandArgs) => Promise<Attachment[]>;
46
+ }
47
+ }
48
+ /**
49
+ * Setup Argos hooks for Vitest.
50
+ */
51
+ declare function setupArgos(): void;
52
+ /**
53
+ * Take an Argos screenshot of a story in Vitest.
54
+ */
55
+ declare function argosScreenshot(story: {
56
+ parameters: Record<string, any>;
57
+ globals: StorybookGlobals | null;
58
+ id: string;
59
+ }, name: string): Promise<void>;
60
+
61
+ export { type ArgosScreenshotOptions, argosScreenshot, setupArgos };
package/dist/vitest.js ADDED
@@ -0,0 +1,45 @@
1
+ // src/vitest.ts
2
+ import { afterEach } from "vitest";
3
+ import { server } from "@vitest/browser/context";
4
+ function setupArgos() {
5
+ afterEach(async (ctx) => {
6
+ const story = "story" in ctx ? ctx.story : null;
7
+ if (!story) {
8
+ throw new Error(
9
+ `@argos-ci/storybook/vitest-plugin should be used with @storybook/addon-vitest/vitest-plugin`
10
+ );
11
+ }
12
+ await server.commands.argosScreenshot({
13
+ name: story.id,
14
+ story: {
15
+ id: story.id,
16
+ parameters: story.parameters,
17
+ globals: story.globals
18
+ },
19
+ test: {
20
+ id: ctx.task.id,
21
+ title: ctx.task.name,
22
+ titlePath: [ctx.task.file.name, ctx.task.name],
23
+ location: {
24
+ line: ctx.task.location?.line ?? 1,
25
+ column: ctx.task.location?.column ?? 1,
26
+ file: ctx.task.file.filepath
27
+ }
28
+ }
29
+ });
30
+ });
31
+ }
32
+ async function argosScreenshot(story, name) {
33
+ await server.commands.argosScreenshot({
34
+ name: `${story.id}/${name}`,
35
+ story: {
36
+ id: story.id,
37
+ parameters: story.parameters,
38
+ globals: story.globals
39
+ }
40
+ });
41
+ }
42
+ export {
43
+ argosScreenshot,
44
+ setupArgos
45
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@argos-ci/storybook",
3
3
  "description": "Visual testing for Storybook test runner.",
4
- "version": "2.1.6",
4
+ "version": "2.1.7",
5
5
  "author": "Smooth Code",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -39,7 +39,7 @@
39
39
  "node": ">=18.16.0"
40
40
  },
41
41
  "dependencies": {
42
- "@argos-ci/playwright": "5.0.8",
42
+ "@argos-ci/playwright": "5.0.9",
43
43
  "@argos-ci/util": "2.3.2"
44
44
  },
45
45
  "peerDependencies": {
@@ -81,5 +81,5 @@
81
81
  "check-format": "prettier --check --ignore-unknown --ignore-path=./.gitignore --ignore-path=../../.gitignore --ignore-path=../../.prettierignore .",
82
82
  "lint": "eslint ."
83
83
  },
84
- "gitHead": "59ebec1a1883175bec3f77a2b885f7f3ef42d7cd"
84
+ "gitHead": "899956c05cad3211eb2dd030a214a2e0af12e27d"
85
85
  }