diff --git a/code/.storybook/vitest.config.ts b/code/.storybook/vitest.config.ts index a9e26b6ddbae..4e7c8fdd87d2 100644 --- a/code/.storybook/vitest.config.ts +++ b/code/.storybook/vitest.config.ts @@ -33,7 +33,7 @@ export default mergeConfig( include: [ // TODO: test all core and addon stories later // './core/**/components/**/*.{story,stories}.?(c|m)[jt]s?(x)', - '../addons/interactions/src/**/*.{story,stories}.?(c|m)[jt]s?(x)', + '../addons/**/src/**/*.{story,stories}.?(c|m)[jt]s?(x)', ], exclude: [ ...defaultExclude, diff --git a/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx b/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx index 0a6cb70831b9..7cb0c52b0113 100644 --- a/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx +++ b/code/addons/onboarding/src/components/HighlightElement/HighlightElement.stories.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -import { expect, within } from '@storybook/test'; +import { expect, waitFor, within } from '@storybook/test'; import { HighlightElement } from './HighlightElement'; @@ -38,7 +38,7 @@ export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement.parentElement!); const button = canvas.getByRole('button'); - await expect(button).toHaveStyle('box-shadow: rgba(2,156,253,1) 0 0 2px 1px'); + await waitFor(() => expect(button).toHaveStyle('box-shadow: rgba(2,156,253,1) 0 0 2px 1px')); }, }; diff --git a/code/addons/vitest/src/plugin/setup-file.test.ts b/code/addons/vitest/src/plugin/setup-file.test.ts new file mode 100644 index 000000000000..35720515074e --- /dev/null +++ b/code/addons/vitest/src/plugin/setup-file.test.ts @@ -0,0 +1,80 @@ +/* eslint-disable no-underscore-dangle */ +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { type Task, modifyErrorMessage } from './setup-file'; + +describe('modifyErrorMessage', () => { + const originalUrl = import.meta.env.__STORYBOOK_URL__; + beforeEach(() => { + import.meta.env.__STORYBOOK_URL__ = 'http://localhost:6006'; + }); + + afterEach(() => { + import.meta.env.__STORYBOOK_URL__ = originalUrl; + }); + + it('should modify the error message if the test is failing and there is a storyId in the task meta', () => { + const task: Task = { + type: 'test', + result: { + state: 'fail', + errors: [{ message: 'Original error message' }], + }, + meta: { storyId: 'my-story' }, + }; + + modifyErrorMessage({ task }); + + expect(task.result?.errors?.[0].message).toMatchInlineSnapshot(` + " + Click to debug the error directly in Storybook: http://localhost:6006/?path=/story/my-story&addonPanel=storybook/interactions/panel + + Original error message" + `); + expect(task.result?.errors?.[0].message).toContain('Original error message'); + }); + + it('should not modify the error message if task type is not "test"', () => { + const task: Task = { + type: 'custom', + result: { + state: 'fail', + errors: [{ message: 'Original error message' }], + }, + meta: { storyId: 'my-story' }, + }; + + modifyErrorMessage({ task }); + + expect(task.result?.errors?.[0].message).toBe('Original error message'); + }); + + it('should not modify the error message if task result state is not "fail"', () => { + const task: Task = { + type: 'test', + result: { + state: 'pass', + }, + meta: { storyId: 'my-story' }, + }; + + modifyErrorMessage({ task }); + + expect(task.result?.errors).toBeUndefined(); + }); + + it('should not modify the error message if meta.storyId is not present', () => { + const task: Task = { + type: 'test', + result: { + state: 'fail', + errors: [{ message: 'Non story test failure' }], + }, + meta: {}, + }; + + modifyErrorMessage({ task }); + + expect(task.result?.errors?.[0].message).toBe('Non story test failure'); + }); +}); diff --git a/code/addons/vitest/src/plugin/setup-file.ts b/code/addons/vitest/src/plugin/setup-file.ts index b5f411e97671..ad3db3807121 100644 --- a/code/addons/vitest/src/plugin/setup-file.ts +++ b/code/addons/vitest/src/plugin/setup-file.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable no-underscore-dangle */ -import { afterAll, vi } from 'vitest'; -import type { RunnerTask, TaskMeta } from 'vitest'; +import { afterEach, vi } from 'vitest'; +import type { RunnerTask } from 'vitest'; import { Channel } from 'storybook/internal/channels'; @@ -13,28 +13,26 @@ declare global { var __STORYBOOK_ADDONS_CHANNEL__: Channel; } -type ExtendedMeta = TaskMeta & { storyId: string; hasPlayFunction: boolean }; +export type Task = Partial & { + meta: Record; +}; const transport = { setHandler: vi.fn(), send: vi.fn() }; -globalThis.__STORYBOOK_ADDONS_CHANNEL__ = new Channel({ transport }); +globalThis.__STORYBOOK_ADDONS_CHANNEL__ ??= new Channel({ transport }); -// The purpose of this set up file is to modify the error message of failed tests -// and inject a link to the story in Storybook -const modifyErrorMessage = (currentTask: RunnerTask) => { - const meta = currentTask.meta as ExtendedMeta; +export const modifyErrorMessage = ({ task }: { task: Task }) => { + const meta = task.meta; if ( - currentTask.type === 'test' && - currentTask.result?.state === 'fail' && + task.type === 'test' && + task.result?.state === 'fail' && meta.storyId && - currentTask.result.errors?.[0] + task.result.errors?.[0] ) { - const currentError = currentTask.result.errors[0]; + const currentError = task.result.errors[0]; const storybookUrl = import.meta.env.__STORYBOOK_URL__; const storyUrl = `${storybookUrl}/?path=/story/${meta.storyId}&addonPanel=storybook/interactions/panel`; currentError.message = `\n\x1B[34mClick to debug the error directly in Storybook: ${storyUrl}\x1B[39m\n\n${currentError.message}`; } }; -afterAll((suite) => { - suite.tasks.forEach(modifyErrorMessage); -}); +afterEach(modifyErrorMessage); diff --git a/code/package.json b/code/package.json index 412f78c1ddd6..98b8d1709af2 100644 --- a/code/package.json +++ b/code/package.json @@ -48,7 +48,7 @@ "storybook:ui": "NODE_OPTIONS=\"--preserve-symlinks --preserve-symlinks-main\" ./lib/cli/bin/index.cjs dev --port 6006 --config-dir ./.storybook", "storybook:ui:build": "NODE_OPTIONS=\"--preserve-symlinks --preserve-symlinks-main\" ./lib/cli/bin/index.cjs build --config-dir ./.storybook --webpack-stats-json", "storybook:ui:chromatic": "../scripts/node_modules/.bin/chromatic --build-script-name storybook:ui:build --storybook-base-dir ./ --exit-zero-on-changes --exit-once-uploaded", - "storybook:vitest": "yarn test --project storybook-ui", + "storybook:vitest": "yarn test:watch --project storybook-ui", "storybook:vitest:inspect": "INSPECT=true yarn test --project storybook-ui", "task": "yarn --cwd ../scripts task", "test": "NODE_OPTIONS=--max_old_space_size=4096 vitest run",