From d236c855025b603bbec6c23b88eca9ccbaf61f98 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 23 Oct 2025 13:53:17 +0200 Subject: [PATCH 01/10] apply extra fixes --- .../vitest/src/vitest-plugin/test-utils.ts | 14 ++++------- .../vitest/src/vitest-plugin/viewports.ts | 4 +++- .../src/vitest-plugin/vitest-context.ts | 24 +++++++++++++++++++ .../vitePlugins/vite-inject-mocker/plugin.ts | 4 +++- .../react/.storybook/preview.tsx | 3 +++ .../react/package.json | 15 ++++++------ 6 files changed, 45 insertions(+), 19 deletions(-) create mode 100644 code/addons/vitest/src/vitest-plugin/vitest-context.ts diff --git a/code/addons/vitest/src/vitest-plugin/test-utils.ts b/code/addons/vitest/src/vitest-plugin/test-utils.ts index c54b2a8b04a8..3dc6a117ab30 100644 --- a/code/addons/vitest/src/vitest-plugin/test-utils.ts +++ b/code/addons/vitest/src/vitest-plugin/test-utils.ts @@ -3,18 +3,10 @@ import { type RunnerTask, type TaskMeta, type TestContext } from 'vitest'; import { type Meta, type Story, getStoryChildren, isStory } from 'storybook/internal/csf'; import type { ComponentAnnotations, ComposedStoryFn, Renderer } from 'storybook/internal/types'; -import { server } from '@vitest/browser/context'; import { type Report, composeStory, getCsfFactoryAnnotations } from 'storybook/preview-api'; import { setViewport } from './viewports'; - -declare module '@vitest/browser/context' { - interface BrowserCommands { - getInitialGlobals: () => Promise>; - } -} - -const { getInitialGlobals } = server.commands; +import { getVitestBrowserContext } from './vitest-context'; /** * Converts a file URL to a file path, handling URL encoding @@ -49,6 +41,10 @@ export const testStory = ( const storyAnnotations = test ? test.input : annotations.story; + const { server } = await getVitestBrowserContext(); + + const { getInitialGlobals } = server.commands; + const composedStory = composeStory( storyAnnotations, annotations.meta!, diff --git a/code/addons/vitest/src/vitest-plugin/viewports.ts b/code/addons/vitest/src/vitest-plugin/viewports.ts index ec2de272cb42..957f283b571d 100644 --- a/code/addons/vitest/src/vitest-plugin/viewports.ts +++ b/code/addons/vitest/src/vitest-plugin/viewports.ts @@ -4,6 +4,8 @@ import { UnsupportedViewportDimensionError } from 'storybook/internal/preview-er import { MINIMAL_VIEWPORTS } from 'storybook/viewport'; import type { ViewportMap } from 'storybook/viewport'; +import { getVitestBrowserContext } from './vitest-context'; + declare global { // eslint-disable-next-line no-var var __vitest_browser__: boolean; @@ -66,7 +68,7 @@ export const setViewport = async (parameters: Parameters = {}, globals: Globals defaultViewport = viewportsParam.defaultViewport; } - const { page } = await import('@vitest/browser/context').catch(() => ({ + const { page } = await getVitestBrowserContext().catch(() => ({ page: null, })); diff --git a/code/addons/vitest/src/vitest-plugin/vitest-context.ts b/code/addons/vitest/src/vitest-plugin/vitest-context.ts new file mode 100644 index 000000000000..8abb51e0eb81 --- /dev/null +++ b/code/addons/vitest/src/vitest-plugin/vitest-context.ts @@ -0,0 +1,24 @@ +import semver from 'semver'; + +type VitestBrowserContext = typeof import('@vitest/browser/context'); + +type VitestServerContext = VitestBrowserContext & { + server: { + commands: typeof import('@vitest/browser/context').server.commands & { + getInitialGlobals: () => Promise>; + }; + }; +}; + +/** Gets the Vitest browser context based on which version of Vitest is installed. */ +export const getVitestBrowserContext = async (): Promise => { + const vitestVersion = await import('vitest/package.json', { with: { type: 'json' } }).then( + (v) => v.version + ); + + if (semver.major(vitestVersion) >= 4) { + return import('@vitest/browser') as unknown as Promise; + } + + return import('@vitest/browser/context') as Promise; +}; diff --git a/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts b/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts index ec468cf21d3e..eca7a64456a1 100644 --- a/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts +++ b/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts @@ -40,13 +40,15 @@ export const viteInjectMockerRuntime = (options: { config() { return { optimizeDeps: { - include: ['@vitest/mocker', '@vitest/mocker/browser'], + include: ['@vitest/mocker', '@vitest/mocker/browser', '@vitest/mocker/node'], + exclude: ['fsevents'], }, resolve: { // Aliasing necessary for package managers like pnpm, since resolving modules from a virtual module // leads to errors, if the imported module is not a dependency of the project. // By resolving the module to the real path, we can avoid this issue. alias: { + '@vitest/mocker/node': fileURLToPath(import.meta.resolve('@vitest/mocker/node')), '@vitest/mocker/browser': fileURLToPath(import.meta.resolve('@vitest/mocker/browser')), '@vitest/mocker': fileURLToPath(import.meta.resolve('@vitest/mocker')), }, diff --git a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx index ee02f0c8d810..b2068ba39f6c 100644 --- a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx +++ b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx @@ -1,6 +1,9 @@ import type { Preview } from '@storybook/react-vite'; +import { sb } from 'storybook/test' import { getDecoratorString } from './get-decorator-string'; +sb.mock('./get-decorator-string.ts', { spy: true }); + console.log('preview file is called!'); const preview: Preview = { diff --git a/test-storybooks/portable-stories-kitchen-sink/react/package.json b/test-storybooks/portable-stories-kitchen-sink/react/package.json index 5eee1e292882..127ad8a00856 100644 --- a/test-storybooks/portable-stories-kitchen-sink/react/package.json +++ b/test-storybooks/portable-stories-kitchen-sink/react/package.json @@ -60,10 +60,10 @@ "devDependencies": { "@playwright/experimental-ct-react": "1.52.0", "@playwright/test": "1.52.0", - "@storybook/addon-a11y": "^8.0.0", - "@storybook/addon-vitest": "^8.0.0", - "@storybook/react": "^8.0.0", - "@storybook/react-vite": "^8.0.0", + "@storybook/addon-a11y": "^10.0.0", + "@storybook/addon-vitest": "^10.0.0", + "@storybook/react": "^10.0.0", + "@storybook/react-vite": "^10.0.0", "@swc/core": "^1.4.2", "@swc/jest": "^0.2.36", "@testing-library/dom": "^10.4.1", @@ -74,8 +74,7 @@ "@types/react-dom": "^19.0.3", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", - "@vitejs/plugin-react": "^4.2.1", - "@vitest/browser": "^4.0.0", + "@vitejs/plugin-react": "^5.0.4", "@vitest/browser-playwright": "^4.0.0", "@vitest/coverage-v8": "^4.0.0", "@vitest/ui": "^4.0.0", @@ -87,9 +86,9 @@ "identity-obj-proxy": "^3.0.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "storybook": "^8.0.0", + "storybook": "^10.0.0", "typescript": "^5.8.3", - "vite": "^5.1.1", + "vite": "^7.1.12", "vitest": "^4.0.0" } } \ No newline at end of file From 80713598bc0db9441d2690c2257fa0783283dbf0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:42:15 +0000 Subject: [PATCH 02/10] Fix: Don't add triple slash reference to vitest.config files Only add `/// ` to vite.config files, not vitest.config files, because vitest.config files already have the vitest/config types available by default. Co-authored-by: yannbf <1671563+yannbf@users.noreply.github.com> --- code/addons/vitest/src/postinstall.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/code/addons/vitest/src/postinstall.ts b/code/addons/vitest/src/postinstall.ts index 82bff176da2c..6bea9c1a0322 100644 --- a/code/addons/vitest/src/postinstall.ts +++ b/code/addons/vitest/src/postinstall.ts @@ -468,11 +468,14 @@ export default async function postInstall(options: PostinstallOptions) { logger.plain(` ${rootConfig}`); const formattedContent = await formatFileContent(rootConfig, generate(target).code); + // Only add triple slash reference to vite.config files, not vitest.config files + // vitest.config files already have the vitest/config types available + const shouldAddReference = !configFileHasTypeReference && !vitestConfigFile; await writeFile( rootConfig, - configFileHasTypeReference - ? formattedContent - : '/// \n' + formattedContent + shouldAddReference + ? '/// \n' + formattedContent + : formattedContent ); } else { logErrors( From ad8d67f3a4b08eac4ed3d97e7455ba4bd0a28abd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:26:04 +0000 Subject: [PATCH 03/10] Fix vitest addon to extract coverage config to top-level test object When transforming vitest configs with coverage settings, the addon now correctly: - Extracts the coverage property from the existing test config - Keeps it at the top-level test object (where it's global) - Moves other test properties to workspace/projects array items - Adds test cases to verify the fix works for both workspace and projects modes Co-authored-by: yannbf <1671563+yannbf@users.noreply.github.com> --- .../vitest/src/updateVitestFile.test.ts | 188 ++++++++++++++++++ code/addons/vitest/src/updateVitestFile.ts | 26 ++- 2 files changed, 213 insertions(+), 1 deletion(-) diff --git a/code/addons/vitest/src/updateVitestFile.test.ts b/code/addons/vitest/src/updateVitestFile.test.ts index a244b23f02ee..04bd87cd375d 100644 --- a/code/addons/vitest/src/updateVitestFile.test.ts +++ b/code/addons/vitest/src/updateVitestFile.test.ts @@ -771,6 +771,194 @@ describe('updateConfigFile', () => { }));" `); }); + + it('extracts coverage config and keeps it at top level when using workspace', async () => { + const source = babel.babelParse( + await loadTemplate('vitest.config.template.ts', { + CONFIG_DIR: '.storybook', + BROWSER_CONFIG: "{ provider: 'playwright' }", + SETUP_FILE: '../.storybook/vitest.setup.ts', + }) + ); + const target = babel.babelParse(` + import { mergeConfig, defineConfig } from 'vitest/config' + import viteConfig from './vite.config' + + export default mergeConfig( + viteConfig, + defineConfig({ + test: { + name: 'node', + environment: 'happy-dom', + include: ['**/*.test.ts'], + coverage: { + exclude: [ + 'storybook.setup.ts', + '**/*.stories.*', + ], + }, + }, + }) + ) + `); + + const before = babel.generate(target).code; + const updated = updateConfigFile(source, target); + expect(updated).toBe(true); + + const after = babel.generate(target).code; + + // check if the code was updated at all + expect(after).not.toBe(before); + + // check if the code was updated correctly + // Coverage should stay at the top level, not moved into the workspace + expect(getDiff(before, after)).toMatchInlineSnapshot(` + " import { mergeConfig, defineConfig } from 'vitest/config'; + import viteConfig from './vite.config'; + + + import path from 'node:path'; + + import { fileURLToPath } from 'node:url'; + + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; + + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); + + + + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon + + + export default mergeConfig(viteConfig, defineConfig({ + test: { + + - name: 'node', + - environment: 'happy-dom', + - include: ['**/*.test.ts'], + - + coverage: { + exclude: ['storybook.setup.ts', '**/*.stories.*'] + + - } + - + + }, + + workspace: [{ + + extends: true, + + test: { + + name: 'node', + + environment: 'happy-dom', + + include: ['**/*.test.ts'] + + } + + }, { + + extends: true, + + plugins: [ + + // The plugin will run tests for the stories defined in your Storybook config + + // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest + + storybookTest({ + + configDir: path.join(dirname, '.storybook') + + })], + + test: { + + name: 'storybook', + + browser: { + + provider: 'playwright' + + }, + + setupFiles: ['../.storybook/vitest.setup.ts'] + + } + + }] + + + } + }));" + `); + }); + + it('extracts coverage config and keeps it at top level when using projects', async () => { + const source = babel.babelParse( + await loadTemplate('vitest.config.3.2.template.ts', { + CONFIG_DIR: '.storybook', + BROWSER_CONFIG: "{ provider: 'playwright' }", + SETUP_FILE: '../.storybook/vitest.setup.ts', + }) + ); + const target = babel.babelParse(` + import { mergeConfig, defineConfig } from 'vitest/config' + import viteConfig from './vite.config' + + export default mergeConfig( + viteConfig, + defineConfig({ + test: { + name: 'node', + environment: 'happy-dom', + include: ['**/*.test.ts'], + coverage: { + exclude: [ + 'storybook.setup.ts', + '**/*.stories.*', + ], + }, + }, + }) + ) + `); + + const before = babel.generate(target).code; + const updated = updateConfigFile(source, target); + expect(updated).toBe(true); + + const after = babel.generate(target).code; + + // check if the code was updated at all + expect(after).not.toBe(before); + + // check if the code was updated correctly + // Coverage should stay at the top level, not moved into the projects + expect(getDiff(before, after)).toMatchInlineSnapshot(` + " import { mergeConfig, defineConfig } from 'vitest/config'; + import viteConfig from './vite.config'; + + + import path from 'node:path'; + + import { fileURLToPath } from 'node:url'; + + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; + + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); + + + + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon + + + export default mergeConfig(viteConfig, defineConfig({ + test: { + + - name: 'node', + - environment: 'happy-dom', + - include: ['**/*.test.ts'], + - + coverage: { + exclude: ['storybook.setup.ts', '**/*.stories.*'] + + - } + - + + }, + + projects: [{ + + extends: true, + + test: { + + name: 'node', + + environment: 'happy-dom', + + include: ['**/*.test.ts'] + + } + + }, { + + extends: true, + + plugins: [ + + // The plugin will run tests for the stories defined in your Storybook config + + // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest + + storybookTest({ + + configDir: path.join(dirname, '.storybook') + + })], + + test: { + + name: 'storybook', + + browser: { + + provider: 'playwright' + + }, + + setupFiles: ['../.storybook/vitest.setup.ts'] + + } + + }] + + + } + }));" + `); + }); }); describe('updateWorkspaceFile', () => { diff --git a/code/addons/vitest/src/updateVitestFile.ts b/code/addons/vitest/src/updateVitestFile.ts index 04af8916ac28..1dd2cd1a404b 100644 --- a/code/addons/vitest/src/updateVitestFile.ts +++ b/code/addons/vitest/src/updateVitestFile.ts @@ -249,6 +249,24 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as workspaceOrProjectsProp && workspaceOrProjectsProp.value.type === 'ArrayExpression' ) { + // Extract coverage config before creating the test project + const coverageProp = existingTestProp.value.properties.find( + (p) => + p.type === 'ObjectProperty' && + p.key.type === 'Identifier' && + p.key.name === 'coverage' + ) as t.ObjectProperty | undefined; + + // Create a new test config without the coverage property + const testPropsWithoutCoverage = existingTestProp.value.properties.filter( + (p) => p !== coverageProp + ); + + const testConfigForProject: t.ObjectExpression = { + type: 'ObjectExpression', + properties: testPropsWithoutCoverage, + }; + // Create the existing test project const existingTestProject: t.ObjectExpression = { type: 'ObjectExpression', @@ -263,7 +281,7 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as { type: 'ObjectProperty', key: { type: 'Identifier', name: 'test' }, - value: existingTestProp.value, + value: testConfigForProject, computed: false, shorthand: false, }, @@ -278,6 +296,12 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as (p) => p !== existingTestProp ); + // If there was a coverage config, add it to the template's test config (at the top level of the test object) + // Insert it at the beginning so it appears before workspace/projects + if (coverageProp && templateTestProp.value.type === 'ObjectExpression') { + templateTestProp.value.properties.unshift(coverageProp); + } + // Merge the template properties (which now include our existing test project in the array) mergeProperties(properties, defineConfigProps.properties); } else { From 423d58b3518b82978a9125e27944e06ae485b71e Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 23 Oct 2025 14:12:25 +0200 Subject: [PATCH 04/10] Revert "Fix vitest addon to extract coverage config to top-level test object" This reverts commit ad8d67f3a4b08eac4ed3d97e7455ba4bd0a28abd. --- .../vitest/src/updateVitestFile.test.ts | 188 ------------------ code/addons/vitest/src/updateVitestFile.ts | 26 +-- 2 files changed, 1 insertion(+), 213 deletions(-) diff --git a/code/addons/vitest/src/updateVitestFile.test.ts b/code/addons/vitest/src/updateVitestFile.test.ts index 04bd87cd375d..a244b23f02ee 100644 --- a/code/addons/vitest/src/updateVitestFile.test.ts +++ b/code/addons/vitest/src/updateVitestFile.test.ts @@ -771,194 +771,6 @@ describe('updateConfigFile', () => { }));" `); }); - - it('extracts coverage config and keeps it at top level when using workspace', async () => { - const source = babel.babelParse( - await loadTemplate('vitest.config.template.ts', { - CONFIG_DIR: '.storybook', - BROWSER_CONFIG: "{ provider: 'playwright' }", - SETUP_FILE: '../.storybook/vitest.setup.ts', - }) - ); - const target = babel.babelParse(` - import { mergeConfig, defineConfig } from 'vitest/config' - import viteConfig from './vite.config' - - export default mergeConfig( - viteConfig, - defineConfig({ - test: { - name: 'node', - environment: 'happy-dom', - include: ['**/*.test.ts'], - coverage: { - exclude: [ - 'storybook.setup.ts', - '**/*.stories.*', - ], - }, - }, - }) - ) - `); - - const before = babel.generate(target).code; - const updated = updateConfigFile(source, target); - expect(updated).toBe(true); - - const after = babel.generate(target).code; - - // check if the code was updated at all - expect(after).not.toBe(before); - - // check if the code was updated correctly - // Coverage should stay at the top level, not moved into the workspace - expect(getDiff(before, after)).toMatchInlineSnapshot(` - " import { mergeConfig, defineConfig } from 'vitest/config'; - import viteConfig from './vite.config'; - - + import path from 'node:path'; - + import { fileURLToPath } from 'node:url'; - + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; - + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); - + - + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon - + - export default mergeConfig(viteConfig, defineConfig({ - test: { - - - name: 'node', - - environment: 'happy-dom', - - include: ['**/*.test.ts'], - - - coverage: { - exclude: ['storybook.setup.ts', '**/*.stories.*'] - - - } - - - + }, - + workspace: [{ - + extends: true, - + test: { - + name: 'node', - + environment: 'happy-dom', - + include: ['**/*.test.ts'] - + } - + }, { - + extends: true, - + plugins: [ - + // The plugin will run tests for the stories defined in your Storybook config - + // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest - + storybookTest({ - + configDir: path.join(dirname, '.storybook') - + })], - + test: { - + name: 'storybook', - + browser: { - + provider: 'playwright' - + }, - + setupFiles: ['../.storybook/vitest.setup.ts'] - + } - + }] - + - } - }));" - `); - }); - - it('extracts coverage config and keeps it at top level when using projects', async () => { - const source = babel.babelParse( - await loadTemplate('vitest.config.3.2.template.ts', { - CONFIG_DIR: '.storybook', - BROWSER_CONFIG: "{ provider: 'playwright' }", - SETUP_FILE: '../.storybook/vitest.setup.ts', - }) - ); - const target = babel.babelParse(` - import { mergeConfig, defineConfig } from 'vitest/config' - import viteConfig from './vite.config' - - export default mergeConfig( - viteConfig, - defineConfig({ - test: { - name: 'node', - environment: 'happy-dom', - include: ['**/*.test.ts'], - coverage: { - exclude: [ - 'storybook.setup.ts', - '**/*.stories.*', - ], - }, - }, - }) - ) - `); - - const before = babel.generate(target).code; - const updated = updateConfigFile(source, target); - expect(updated).toBe(true); - - const after = babel.generate(target).code; - - // check if the code was updated at all - expect(after).not.toBe(before); - - // check if the code was updated correctly - // Coverage should stay at the top level, not moved into the projects - expect(getDiff(before, after)).toMatchInlineSnapshot(` - " import { mergeConfig, defineConfig } from 'vitest/config'; - import viteConfig from './vite.config'; - - + import path from 'node:path'; - + import { fileURLToPath } from 'node:url'; - + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; - + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); - + - + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon - + - export default mergeConfig(viteConfig, defineConfig({ - test: { - - - name: 'node', - - environment: 'happy-dom', - - include: ['**/*.test.ts'], - - - coverage: { - exclude: ['storybook.setup.ts', '**/*.stories.*'] - - - } - - - + }, - + projects: [{ - + extends: true, - + test: { - + name: 'node', - + environment: 'happy-dom', - + include: ['**/*.test.ts'] - + } - + }, { - + extends: true, - + plugins: [ - + // The plugin will run tests for the stories defined in your Storybook config - + // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest - + storybookTest({ - + configDir: path.join(dirname, '.storybook') - + })], - + test: { - + name: 'storybook', - + browser: { - + provider: 'playwright' - + }, - + setupFiles: ['../.storybook/vitest.setup.ts'] - + } - + }] - + - } - }));" - `); - }); }); describe('updateWorkspaceFile', () => { diff --git a/code/addons/vitest/src/updateVitestFile.ts b/code/addons/vitest/src/updateVitestFile.ts index 1dd2cd1a404b..04af8916ac28 100644 --- a/code/addons/vitest/src/updateVitestFile.ts +++ b/code/addons/vitest/src/updateVitestFile.ts @@ -249,24 +249,6 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as workspaceOrProjectsProp && workspaceOrProjectsProp.value.type === 'ArrayExpression' ) { - // Extract coverage config before creating the test project - const coverageProp = existingTestProp.value.properties.find( - (p) => - p.type === 'ObjectProperty' && - p.key.type === 'Identifier' && - p.key.name === 'coverage' - ) as t.ObjectProperty | undefined; - - // Create a new test config without the coverage property - const testPropsWithoutCoverage = existingTestProp.value.properties.filter( - (p) => p !== coverageProp - ); - - const testConfigForProject: t.ObjectExpression = { - type: 'ObjectExpression', - properties: testPropsWithoutCoverage, - }; - // Create the existing test project const existingTestProject: t.ObjectExpression = { type: 'ObjectExpression', @@ -281,7 +263,7 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as { type: 'ObjectProperty', key: { type: 'Identifier', name: 'test' }, - value: testConfigForProject, + value: existingTestProp.value, computed: false, shorthand: false, }, @@ -296,12 +278,6 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as (p) => p !== existingTestProp ); - // If there was a coverage config, add it to the template's test config (at the top level of the test object) - // Insert it at the beginning so it appears before workspace/projects - if (coverageProp && templateTestProp.value.type === 'ObjectExpression') { - templateTestProp.value.properties.unshift(coverageProp); - } - // Merge the template properties (which now include our existing test project in the array) mergeProperties(properties, defineConfigProps.properties); } else { From 9f996c3ed264cd27ceec4fc9470443f19584c559 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 23 Oct 2025 15:51:18 +0200 Subject: [PATCH 05/10] Update Vitest dependencies and refactor imports - Removed optional peer dependencies for `@vitest/browser-playwright` and `vitest` in package.json and yarn.lock. - Updated import statement in `vitest-context.ts` to use `vitest/browser` instead of `@vitest/browser`. - Adjusted dependency inclusion in `vite-inject-mocker/plugin.ts` for better readability. - Added `@vitest/browser` as a direct dependency in the portable stories kitchen sink package.json. These changes streamline the Vitest integration and ensure compatibility with version 4.0.0. --- code/addons/vitest/package.json | 10 ---------- .../vitest/src/vitest-plugin/vitest-context.ts | 2 +- .../presets/vitePlugins/vite-inject-mocker/plugin.ts | 12 ++++++++++-- code/yarn.lock | 7 ------- .../portable-stories-kitchen-sink/react/package.json | 3 ++- 5 files changed, 13 insertions(+), 21 deletions(-) diff --git a/code/addons/vitest/package.json b/code/addons/vitest/package.json index 03b462a58e1b..af87fd53e172 100644 --- a/code/addons/vitest/package.json +++ b/code/addons/vitest/package.json @@ -105,23 +105,13 @@ }, "peerDependencies": { "@vitest/browser": "^3.0.0 || ^4.0.0", - "@vitest/browser-playwright": "^4.0.0", "@vitest/runner": "^3.0.0 || ^4.0.0", "storybook": "workspace:^", "vitest": "^3.0.0 || ^4.0.0" }, "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, "@vitest/runner": { "optional": true - }, - "vitest": { - "optional": true } }, "publishConfig": { diff --git a/code/addons/vitest/src/vitest-plugin/vitest-context.ts b/code/addons/vitest/src/vitest-plugin/vitest-context.ts index 8abb51e0eb81..68a61c544a56 100644 --- a/code/addons/vitest/src/vitest-plugin/vitest-context.ts +++ b/code/addons/vitest/src/vitest-plugin/vitest-context.ts @@ -17,7 +17,7 @@ export const getVitestBrowserContext = async (): Promise => ); if (semver.major(vitestVersion) >= 4) { - return import('@vitest/browser') as unknown as Promise; + return import('vitest/browser') as unknown as Promise; } return import('@vitest/browser/context') as Promise; diff --git a/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts b/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts index eca7a64456a1..95a3444d3d8a 100644 --- a/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts +++ b/code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts @@ -40,8 +40,16 @@ export const viteInjectMockerRuntime = (options: { config() { return { optimizeDeps: { - include: ['@vitest/mocker', '@vitest/mocker/browser', '@vitest/mocker/node'], - exclude: ['fsevents'], + include: [ + // + '@vitest/mocker', + '@vitest/mocker/browser', + '@vitest/mocker/node', + ], + exclude: [ + // + 'fsevents', + ], }, resolve: { // Aliasing necessary for package managers like pnpm, since resolving modules from a virtual module diff --git a/code/yarn.lock b/code/yarn.lock index 36e6bdc78f28..b52fdee19980 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6237,19 +6237,12 @@ __metadata: vitest: "npm:^4.0.1" peerDependencies: "@vitest/browser": ^3.0.0 || ^4.0.0 - "@vitest/browser-playwright": ^4.0.0 "@vitest/runner": ^3.0.0 || ^4.0.0 storybook: "workspace:^" vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: - "@vitest/browser": - optional: true - "@vitest/browser-playwright": - optional: true "@vitest/runner": optional: true - vitest: - optional: true languageName: unknown linkType: soft diff --git a/test-storybooks/portable-stories-kitchen-sink/react/package.json b/test-storybooks/portable-stories-kitchen-sink/react/package.json index 127ad8a00856..7de0fd04ec36 100644 --- a/test-storybooks/portable-stories-kitchen-sink/react/package.json +++ b/test-storybooks/portable-stories-kitchen-sink/react/package.json @@ -75,6 +75,7 @@ "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^4.0.0", "@vitest/browser-playwright": "^4.0.0", "@vitest/coverage-v8": "^4.0.0", "@vitest/ui": "^4.0.0", @@ -91,4 +92,4 @@ "vite": "^7.1.12", "vitest": "^4.0.0" } -} \ No newline at end of file +} From 10aba50983adcc703c2cae20fd8014b85d646ed9 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 23 Oct 2025 16:22:26 +0200 Subject: [PATCH 06/10] upgrade cypress in kitchen sink example --- .../portable-stories-kitchen-sink/react/.storybook/preview.tsx | 3 --- .../react/cypress/support/component.ts | 2 +- .../portable-stories-kitchen-sink/react/package.json | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx index b2068ba39f6c..ee02f0c8d810 100644 --- a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx +++ b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx @@ -1,9 +1,6 @@ import type { Preview } from '@storybook/react-vite'; -import { sb } from 'storybook/test' import { getDecoratorString } from './get-decorator-string'; -sb.mock('./get-decorator-string.ts', { spy: true }); - console.log('preview file is called!'); const preview: Preview = { diff --git a/test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts b/test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts index 455075197889..f4db8361a3f4 100644 --- a/test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts +++ b/test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts @@ -17,7 +17,7 @@ // Import commands.js using ES2015 syntax: import "./commands"; -import { mount } from "cypress/react18"; +import { mount } from "cypress/react"; import { setProjectAnnotations } from "@storybook/react-vite"; import sbAnnotations from "../../.storybook/preview"; diff --git a/test-storybooks/portable-stories-kitchen-sink/react/package.json b/test-storybooks/portable-stories-kitchen-sink/react/package.json index 7de0fd04ec36..ae7643bfc4e8 100644 --- a/test-storybooks/portable-stories-kitchen-sink/react/package.json +++ b/test-storybooks/portable-stories-kitchen-sink/react/package.json @@ -79,7 +79,7 @@ "@vitest/browser-playwright": "^4.0.0", "@vitest/coverage-v8": "^4.0.0", "@vitest/ui": "^4.0.0", - "cypress": "^13.6.4", + "cypress": "^15.5.0", "eslint": "^8.56.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", From 2e5c563d965c884412add7d3fa65f6b257cb2422 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 23 Oct 2025 17:20:53 +0200 Subject: [PATCH 07/10] try aliasing solution for browser context --- code/addons/vitest/build-config.ts | 10 ++ code/addons/vitest/package.json | 4 +- code/addons/vitest/src/vitest-plugin/index.ts | 23 +++ .../vitest/src/vitest-plugin/test-utils.ts | 7 +- code/addons/vitest/src/vitest-plugin/types.ts | 19 +++ .../vitest/src/vitest-plugin/viewports.ts | 7 +- .../vitest-plugin/vitest-context-legacy.ts | 1 + .../vitest-plugin/vitest-context-modern.ts | 1 + code/yarn.lock | 154 +----------------- 9 files changed, 70 insertions(+), 156 deletions(-) create mode 100644 code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts create mode 100644 code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts diff --git a/code/addons/vitest/build-config.ts b/code/addons/vitest/build-config.ts index db187f466942..a4203fcee24f 100644 --- a/code/addons/vitest/build-config.ts +++ b/code/addons/vitest/build-config.ts @@ -22,6 +22,16 @@ const config: BuildEntries = { entryPoint: './src/vitest-plugin/test-utils.ts', dts: false, }, + { + exportEntries: ['./internal/vitest-context'], + entryPoint: './src/vitest-plugin/vitest-context.ts', + dts: false, + }, + { + exportEntries: ['./internal/vitest-context-legacy'], + entryPoint: './src/vitest-plugin/vitest-context-legacy.ts', + dts: false, + }, ], node: [ { diff --git a/code/addons/vitest/package.json b/code/addons/vitest/package.json index af87fd53e172..5e0b8eb62fc1 100644 --- a/code/addons/vitest/package.json +++ b/code/addons/vitest/package.json @@ -46,6 +46,8 @@ "./internal/global-setup": "./dist/vitest-plugin/global-setup.js", "./internal/setup-file": "./dist/vitest-plugin/setup-file.js", "./internal/test-utils": "./dist/vitest-plugin/test-utils.js", + "./internal/vitest-context": "./dist/vitest-plugin/vitest-context.js", + "./internal/vitest-context-legacy": "./dist/vitest-plugin/vitest-context-legacy.js", "./manager": "./dist/manager.js", "./package.json": "./package.json", "./postinstall": "./dist/postinstall.js", @@ -101,7 +103,7 @@ "tree-kill": "^1.2.2", "ts-dedent": "^2.2.0", "typescript": "^5.8.3", - "vitest": "^4.0.1" + "vitest": "^3.2.4" }, "peerDependencies": { "@vitest/browser": "^3.0.0 || ^4.0.0", diff --git a/code/addons/vitest/src/vitest-plugin/index.ts b/code/addons/vitest/src/vitest-plugin/index.ts index 4d4981797291..d721a7ac1f41 100644 --- a/code/addons/vitest/src/vitest-plugin/index.ts +++ b/code/addons/vitest/src/vitest-plugin/index.ts @@ -26,6 +26,7 @@ import type { Presets } from 'storybook/internal/types'; import { match } from 'micromatch'; import { dirname, join, normalize, relative, resolve, sep } from 'pathe'; import picocolors from 'picocolors'; +import semver from 'semver'; import sirv from 'sirv'; import { dedent } from 'ts-dedent'; @@ -97,6 +98,16 @@ const mdxStubPlugin: Plugin = { }, }; +export const checkIsVitest4orHigher = async () => { + const vitestVersion = await import('vitest/package.json', { with: { type: 'json' } }).then( + (pkg) => { + return pkg.default.version; + } + ); + + return semver.major(vitestVersion) >= 4; +}; + export const storybookTest = async (options?: UserOptions): Promise => { const finalOptions = { ...defaultOptions, @@ -123,6 +134,8 @@ export const storybookTest = async (options?: UserOptions): Promise => // We are overriding the environment variable to 'true' if vitest runs via @storybook/addon-vitest's backend const isVitestStorybook = optionalEnvToBoolean(process.env.VITEST_STORYBOOK); + const isVitest4OrHigher = await checkIsVitest4orHigher(); + const directories = { configDir: finalOptions.configDir, workingDir: WORKING_DIR, @@ -175,6 +188,10 @@ export const storybookTest = async (options?: UserOptions): Promise => plugins.push(mdxStubPlugin); } + const addonVitestPath = dirname( + fileURLToPath(import.meta.resolve('@storybook/addon-vitest/package.json')) + ); + const storybookTestPlugin: Plugin = { name: 'vite-plugin-storybook-test', async transformIndexHtml(html) { @@ -307,6 +324,11 @@ export const storybookTest = async (options?: UserOptions): Promise => ), resolve: { + alias: { + '@storybook/addon-vitest/internal/vitest-context': isVitest4OrHigher + ? join(addonVitestPath, 'dist/vitest-plugin/vitest-context.js') + : join(addonVitestPath, 'dist/vitest-plugin/vitest-context-legacy.js'), + }, conditions: [ 'storybook', 'stories', @@ -325,6 +347,7 @@ export const storybookTest = async (options?: UserOptions): Promise => '@storybook/addon-vitest/internal/setup-file', '@storybook/addon-vitest/internal/global-setup', '@storybook/addon-vitest/internal/test-utils', + '@storybook/addon-vitest/internal/vitest-context', ...(frameworkName?.includes('react') || frameworkName?.includes('nextjs') ? ['react-dom/test-utils'] : []), diff --git a/code/addons/vitest/src/vitest-plugin/test-utils.ts b/code/addons/vitest/src/vitest-plugin/test-utils.ts index 3dc6a117ab30..48131a5aa517 100644 --- a/code/addons/vitest/src/vitest-plugin/test-utils.ts +++ b/code/addons/vitest/src/vitest-plugin/test-utils.ts @@ -5,8 +5,8 @@ import type { ComponentAnnotations, ComposedStoryFn, Renderer } from 'storybook/ import { type Report, composeStory, getCsfFactoryAnnotations } from 'storybook/preview-api'; +import type { VitestBrowserContext } from './types'; import { setViewport } from './viewports'; -import { getVitestBrowserContext } from './vitest-context'; /** * Converts a file URL to a file path, handling URL encoding @@ -41,7 +41,10 @@ export const testStory = ( const storyAnnotations = test ? test.input : annotations.story; - const { server } = await getVitestBrowserContext(); + const { server } = (await import( + // @ts-expect-error - This is an internal alias that will be resolved by the vitest plugin at runtime + '@storybook/addon-vitest/internal/vitest-context' + )) as unknown as VitestBrowserContext; const { getInitialGlobals } = server.commands; diff --git a/code/addons/vitest/src/vitest-plugin/types.ts b/code/addons/vitest/src/vitest-plugin/types.ts index 4f071ec1a03d..5a9832d77d84 100644 --- a/code/addons/vitest/src/vitest-plugin/types.ts +++ b/code/addons/vitest/src/vitest-plugin/types.ts @@ -1,3 +1,22 @@ +import type { BrowserCommands, BrowserPage } from '@vitest/browser/context'; + +interface GetInitialGlobalsResult { + a11y?: { + manual?: boolean; + }; +} + +interface ExtendedBrowserCommands extends BrowserCommands { + getInitialGlobals?: () => Promise; +} + +export interface VitestBrowserContext { + page: BrowserPage; + server: { + commands: ExtendedBrowserCommands; + }; +} + export type UserOptions = { /** * The directory where the Storybook configuration is located, relative to the vitest diff --git a/code/addons/vitest/src/vitest-plugin/viewports.ts b/code/addons/vitest/src/vitest-plugin/viewports.ts index 957f283b571d..2bed7f4db112 100644 --- a/code/addons/vitest/src/vitest-plugin/viewports.ts +++ b/code/addons/vitest/src/vitest-plugin/viewports.ts @@ -4,7 +4,7 @@ import { UnsupportedViewportDimensionError } from 'storybook/internal/preview-er import { MINIMAL_VIEWPORTS } from 'storybook/viewport'; import type { ViewportMap } from 'storybook/viewport'; -import { getVitestBrowserContext } from './vitest-context'; +import type { VitestBrowserContext } from './types'; declare global { // eslint-disable-next-line no-var @@ -68,9 +68,10 @@ export const setViewport = async (parameters: Parameters = {}, globals: Globals defaultViewport = viewportsParam.defaultViewport; } - const { page } = await getVitestBrowserContext().catch(() => ({ + // @ts-expect-error - This is an internal alias that will be resolved by the vitest plugin at runtime + const { page } = (await import('@storybook/addon-vitest/internal/vitest-context').catch(() => ({ page: null, - })); + }))) as unknown as VitestBrowserContext; if (!page || !globalThis.__vitest_browser__) { return; diff --git a/code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts b/code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts new file mode 100644 index 000000000000..0e67c325b0da --- /dev/null +++ b/code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts @@ -0,0 +1 @@ +export * from '@vitest/browser/context'; diff --git a/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts b/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts new file mode 100644 index 000000000000..48ae5148928d --- /dev/null +++ b/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts @@ -0,0 +1 @@ +export * from 'vitest/browser'; diff --git a/code/yarn.lock b/code/yarn.lock index b52fdee19980..cf5fa22c2cad 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6234,7 +6234,7 @@ __metadata: tree-kill: "npm:^1.2.2" ts-dedent: "npm:^2.2.0" typescript: "npm:^5.8.3" - vitest: "npm:^4.0.1" + vitest: "npm:^3.2.4" peerDependencies: "@vitest/browser": ^3.0.0 || ^4.0.0 "@vitest/runner": ^3.0.0 || ^4.0.0 @@ -8723,20 +8723,6 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:4.0.1": - version: 4.0.1 - resolution: "@vitest/expect@npm:4.0.1" - dependencies: - "@standard-schema/spec": "npm:^1.0.0" - "@types/chai": "npm:^5.2.2" - "@vitest/spy": "npm:4.0.1" - "@vitest/utils": "npm:4.0.1" - chai: "npm:^6.0.1" - tinyrainbow: "npm:^3.0.3" - checksum: 10c0/11c5049fe5960fb8403ede0dbdc7c25ac9a9c6eadfc7f9ae5a59cf9e71a44f025ec8a93363aca838ae9cd672ea2f66a735d44246ae1f05005b45b70f09b2e138 - languageName: node - linkType: hard - "@vitest/expect@patch:@vitest/expect@npm%3A3.2.4#~/.yarn/patches/@vitest-expect-npm-3.2.4-97c526d5cc.patch": version: 3.2.4 resolution: "@vitest/expect@patch:@vitest/expect@npm%3A3.2.4#~/.yarn/patches/@vitest-expect-npm-3.2.4-97c526d5cc.patch::version=3.2.4&hash=6385de" @@ -8817,7 +8803,7 @@ __metadata: languageName: node linkType: hard -"@vitest/runner@npm:4.0.1, @vitest/runner@npm:^4.0.1": +"@vitest/runner@npm:^4.0.1": version: 4.0.1 resolution: "@vitest/runner@npm:4.0.1" dependencies: @@ -8838,17 +8824,6 @@ __metadata: languageName: node linkType: hard -"@vitest/snapshot@npm:4.0.1": - version: 4.0.1 - resolution: "@vitest/snapshot@npm:4.0.1" - dependencies: - "@vitest/pretty-format": "npm:4.0.1" - magic-string: "npm:^0.30.19" - pathe: "npm:^2.0.3" - checksum: 10c0/50fde1be5c3df22ae45acb3885007b8a332595150468fe0ac23efb366efb4b621e4ce7e9c7e81537fd2eb89db1c1798c8ffcb151890645829d497e797f243761 - languageName: node - linkType: hard - "@vitest/spy@npm:3.2.4": version: 3.2.4 resolution: "@vitest/spy@npm:3.2.4" @@ -11112,13 +11087,6 @@ __metadata: languageName: node linkType: hard -"chai@npm:^6.0.1": - version: 6.2.0 - resolution: "chai@npm:6.2.0" - checksum: 10c0/a4b7d7f5907187e09f1847afa838d6d1608adc7d822031b7900813c4ed5d9702911ac2468bf290676f22fddb3d727b1be90b57c1d0a69b902534ee29cdc6ff8a - languageName: node - linkType: hard - "chalk@npm:5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" @@ -12368,7 +12336,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.6, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3": +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.6, debug@npm:^4.4.0, debug@npm:^4.4.1": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -14680,7 +14648,7 @@ __metadata: languageName: node linkType: hard -"expect-type@npm:^1.2.1, expect-type@npm:^1.2.2": +"expect-type@npm:^1.2.1": version: 1.2.2 resolution: "expect-type@npm:1.2.2" checksum: 10c0/6019019566063bbc7a690d9281d920b1a91284a4a093c2d55d71ffade5ac890cf37a51e1da4602546c4b56569d2ad2fc175a2ccee77d1ae06cb3af91ef84f44b @@ -26682,61 +26650,6 @@ __metadata: languageName: node linkType: hard -"vite@npm:^6.0.0 || ^7.0.0": - version: 7.1.12 - resolution: "vite@npm:7.1.12" - dependencies: - esbuild: "npm:^0.25.0" - fdir: "npm:^6.5.0" - fsevents: "npm:~2.3.3" - picomatch: "npm:^4.0.3" - postcss: "npm:^8.5.6" - rollup: "npm:^4.43.0" - tinyglobby: "npm:^0.2.15" - peerDependencies: - "@types/node": ^20.19.0 || >=22.12.0 - jiti: ">=1.21.0" - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: ">=0.54.8" - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - dependenciesMeta: - fsevents: - optional: true - peerDependenciesMeta: - "@types/node": - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - bin: - vite: bin/vite.js - checksum: 10c0/cef4d4b4a84e663e09b858964af36e916892ac8540068df42a05ced637ceeae5e9ef71c72d54f3cfc1f3c254af16634230e221b6e2327c2a66d794bb49203262 - languageName: node - linkType: hard - "vitefu@npm:^1.1.1": version: 1.1.1 resolution: "vitefu@npm:1.1.1" @@ -26821,65 +26734,6 @@ __metadata: languageName: node linkType: hard -"vitest@npm:^4.0.1": - version: 4.0.1 - resolution: "vitest@npm:4.0.1" - dependencies: - "@vitest/expect": "npm:4.0.1" - "@vitest/mocker": "npm:4.0.1" - "@vitest/pretty-format": "npm:4.0.1" - "@vitest/runner": "npm:4.0.1" - "@vitest/snapshot": "npm:4.0.1" - "@vitest/spy": "npm:4.0.1" - "@vitest/utils": "npm:4.0.1" - debug: "npm:^4.4.3" - es-module-lexer: "npm:^1.7.0" - expect-type: "npm:^1.2.2" - magic-string: "npm:^0.30.19" - pathe: "npm:^2.0.3" - picomatch: "npm:^4.0.3" - std-env: "npm:^3.9.0" - tinybench: "npm:^2.9.0" - tinyexec: "npm:^0.3.2" - tinyglobby: "npm:^0.2.15" - tinyrainbow: "npm:^3.0.3" - vite: "npm:^6.0.0 || ^7.0.0" - why-is-node-running: "npm:^2.3.0" - peerDependencies: - "@edge-runtime/vm": "*" - "@types/debug": ^4.1.12 - "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 - "@vitest/browser-playwright": 4.0.1 - "@vitest/browser-preview": 4.0.1 - "@vitest/browser-webdriverio": 4.0.1 - "@vitest/ui": 4.0.1 - happy-dom: "*" - jsdom: "*" - peerDependenciesMeta: - "@edge-runtime/vm": - optional: true - "@types/debug": - optional: true - "@types/node": - optional: true - "@vitest/browser-playwright": - optional: true - "@vitest/browser-preview": - optional: true - "@vitest/browser-webdriverio": - optional: true - "@vitest/ui": - optional: true - happy-dom: - optional: true - jsdom: - optional: true - bin: - vitest: vitest.mjs - checksum: 10c0/e1276e9b36643dde1c3aace3dc174c058139ce41ada92979f1ff23fc59885291378f709536c7965205774c3da03690b2874544d46e753a48eb292f5da07cf5cc - languageName: node - linkType: hard - "vlq@npm:^0.2.1": version: 0.2.3 resolution: "vlq@npm:0.2.3" From f155516e14a5c9611ae1ba614ec26be43cdb2065 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 23 Oct 2025 22:42:44 +0200 Subject: [PATCH 08/10] fix typing due to switching to use vitest 3 locally --- code/addons/vitest/src/node/reporter.ts | 1 - code/addons/vitest/src/node/vitest-manager.ts | 1 - code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts | 2 ++ code/addons/vitest/src/vitest-plugin/vitest-context.ts | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/addons/vitest/src/node/reporter.ts b/code/addons/vitest/src/node/reporter.ts index d8246fcc119f..f8bfe835bd2e 100644 --- a/code/addons/vitest/src/node/reporter.ts +++ b/code/addons/vitest/src/node/reporter.ts @@ -61,7 +61,6 @@ export class StorybookReporter implements Reporter { this.ctx.state.idMap.clear(); this.ctx.state.errorsSet.clear(); // TODO: Remove this once we don't support Vitest < 4 - // @ts-expect-error processTimeoutCauses does not exist in Vitest 4 this.ctx.state.processTimeoutCauses?.clear(); } } diff --git a/code/addons/vitest/src/node/vitest-manager.ts b/code/addons/vitest/src/node/vitest-manager.ts index 4fd82d3a4437..6f590e7d7712 100644 --- a/code/addons/vitest/src/node/vitest-manager.ts +++ b/code/addons/vitest/src/node/vitest-manager.ts @@ -164,7 +164,6 @@ export class VitestManager { } private updateLastChanged(filepath: string) { - // @ts-expect-error `server` only exists in Vitest 3 this.vitest!.projects.forEach(({ browser, vite, server }) => { if (server) { const serverMods = server.moduleGraph.getModulesByFile(filepath); diff --git a/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts b/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts index 48ae5148928d..27193dcfc22d 100644 --- a/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts +++ b/code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts @@ -1 +1,3 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore (vitest/browser is vitest 4 only, and we're using vitest 3 locally) export * from 'vitest/browser'; diff --git a/code/addons/vitest/src/vitest-plugin/vitest-context.ts b/code/addons/vitest/src/vitest-plugin/vitest-context.ts index 68a61c544a56..3059fc6547d4 100644 --- a/code/addons/vitest/src/vitest-plugin/vitest-context.ts +++ b/code/addons/vitest/src/vitest-plugin/vitest-context.ts @@ -17,6 +17,8 @@ export const getVitestBrowserContext = async (): Promise => ); if (semver.major(vitestVersion) >= 4) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore (vitest/browser is vitest 4 only, and we're using vitest 3 locally) return import('vitest/browser') as unknown as Promise; } From a97e3b53f448be5a186a5476bed56859c50db27d Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 24 Oct 2025 09:24:35 +0200 Subject: [PATCH 09/10] Update viewport test to use internal vitest context alias - Changed import statement for `page` to use the internal vitest context from `@storybook/addon-vitest/internal/vitest-context`. - Updated mock for `@vitest/browser/context` to reflect the new import path. These changes ensure compatibility with the latest Vitest plugin structure. --- code/addons/vitest/src/vitest-plugin/viewports.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/addons/vitest/src/vitest-plugin/viewports.test.ts b/code/addons/vitest/src/vitest-plugin/viewports.test.ts index 5ab205aa36f8..37ca946fb60c 100644 --- a/code/addons/vitest/src/vitest-plugin/viewports.test.ts +++ b/code/addons/vitest/src/vitest-plugin/viewports.test.ts @@ -1,6 +1,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { page } from '@vitest/browser/context'; +// @ts-expect-error - This is an internal alias that will be resolved by the vitest plugin at runtime +import { page } from '@storybook/addon-vitest/internal/vitest-context'; + import { INITIAL_VIEWPORTS } from 'storybook/viewport'; import { @@ -10,7 +12,7 @@ import { setViewport, } from './viewports'; -vi.mock('@vitest/browser/context', () => ({ +vi.mock('@storybook/addon-vitest/internal/vitest-context', () => ({ page: { viewport: vi.fn(), }, From 87a26808505578207a2f12c6741cbafe4415495b Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 24 Oct 2025 10:37:11 +0200 Subject: [PATCH 10/10] Reduce parallelism for e2e-dev workflow from 29 to 28 in CircleCI configuration files. --- .circleci/config.yml | 2 +- .circleci/src/workflows/daily.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dad9f8dd5ef1..60a5b6db83f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1003,7 +1003,7 @@ workflows: requires: - create-sandboxes - e2e-dev: - parallelism: 29 + parallelism: 28 requires: - create-sandboxes - test-runner-production: diff --git a/.circleci/src/workflows/daily.yml b/.circleci/src/workflows/daily.yml index 1aff22c4fd5c..be7814aba520 100644 --- a/.circleci/src/workflows/daily.yml +++ b/.circleci/src/workflows/daily.yml @@ -46,7 +46,7 @@ jobs: requires: - create-sandboxes - e2e-dev: - parallelism: 29 + parallelism: 28 requires: - create-sandboxes - test-runner-production: