Skip to content

Conversation

@valentinpalkovic
Copy link
Contributor

@valentinpalkovic valentinpalkovic commented Oct 1, 2025

Closes #32803, #32804, #32806

What I did

Added Vitest 4 support for @storybook/addon-vitest by:

  • adjusting the postinstall script
  • adjusting the node runner of @storybook/addon-vitest

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-32600-sha-ad8d67f3. Try it out in a new sandbox by running npx [email protected] sandbox or in an existing project with npx [email protected] upgrade.

More information
Published version 0.0.0-pr-32600-sha-ad8d67f3
Triggered by @yannbf
Repository storybookjs/storybook
Branch valentin/vitest-4-support
Commit ad8d67f3
Datetime Thu Oct 23 12:02:49 UTC 2025 (1761220969)
Workflow run 18747659562

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=32600

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for multiple Vitest versions (3.2+ and 4.x) with automatic version detection.
    • Improved browser context handling for cross-version compatibility.
  • Chores

    • Updated test storybook dependencies to align with Vitest 4.x ecosystem.
    • Refined internal module resolution for better version-aware configuration.

@valentinpalkovic valentinpalkovic self-assigned this Oct 1, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 1, 2025

📝 Walkthrough

Walkthrough

The pull request adds comprehensive Vitest 3.x and 4.x version compatibility to the vitest addon by introducing version-aware branching, dynamic context imports, and new internal export paths. This prevents import-time failures and handles breaking changes between Vitest versions.

Changes

Cohort / File(s) Summary
Package configuration & exports
code/addons/vitest/package.json, code/addons/vitest/build-config.ts
Added two new internal public exports (./internal/vitest-context and ./internal/vitest-context-legacy) and build entries. Removed @vitest/browser-playwright from peerDependencies; downgraded vitest devDependency from ^4.0.1 to ^3.2.4; removed optional declarations for @vitest/browser and vitest.
Vitest context modules
code/addons/vitest/src/vitest-plugin/vitest-context.ts, code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts, code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts, code/addons/vitest/src/vitest-plugin/types.ts
Introduced three new context modules: vitest-context.ts (dynamically resolves version-appropriate context), vitest-context-legacy.ts (re-exports @vitest/browser/context), vitest-context-modern.ts (re-exports vitest/browser). Added VitestBrowserContext and VitestServerContext type aliases; added ExtendedBrowserCommands interface with optional getInitialGlobals().
Plugin runtime
code/addons/vitest/src/vitest-plugin/index.ts, code/addons/vitest/src/vitest-plugin/test-utils.ts
Introduced checkIsVitest4orHigher() helper and conditional alias resolution based on Vitest version. Replaced static @vitest/browser/context imports with dynamic imports from @storybook/addon-vitest/internal/vitest-context. Added convertToFilePath() utility for URL/file path handling.
Viewport & browser context
code/addons/vitest/src/vitest-plugin/viewports.ts, code/addons/vitest/src/vitest-plugin/viewports.test.ts
Updated imports to use @storybook/addon-vitest/internal/vitest-context instead of static @vitest/browser/context. Removed ViewportStyles import.
Node-layer updates
code/addons/vitest/src/node/vitest-manager.ts, code/addons/vitest/src/node/reporter.ts
Updated updateLastChanged() to iterate over this.vitest!.projects and invalidate vite moduleGraph. Changed isStorybookProject() signature to accept only TestProject. Added optional chaining in clearVitestState() for Vitest < 4 compatibility.
Installation & setup
code/addons/vitest/src/postinstall.ts
Introduced version-aware branching (isVitest3_2To4, isVitest4OrNewer). Reworked dependency installation with uniqueDependencies to avoid reinstalls. Added getTemplateName() helper for template selection (4.x, 3.2, or default). Removed vitest.projects support; uses vitest.workspace as sole workspace indicator. Updated Vitest shim references and template loading paths. Consolidated addon-a11y setup invocation.
Vite mocker plugin
code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
Added @vitest/mocker/node to optimizeDeps.include, added fsevents exclude, and introduced explicit alias for @vitest/mocker/node.
Test kitchen sink
test-storybooks/portable-stories-kitchen-sink/react/package.json, test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts
Upgraded Storybook packages to 10.x; updated Vitest to ^4.0.0 and added @vitest/browser-playwright (4.0.0). Updated Cypress mount import from cypress/react18 to cypress/react.

Sequence Diagram(s)

sequenceDiagram
    participant Plugin as vitest-plugin/index.ts
    participant CheckHelper as checkIsVitest4orHigher()
    participant PkgJson as vitest/package.json
    participant Vite as Vite Config
    
    Plugin->>CheckHelper: read Vitest version
    CheckHelper->>PkgJson: dynamically import + semver check
    alt Vitest >= 4
        CheckHelper-->>Plugin: true
        Plugin->>Vite: alias '@storybook/addon-vitest/internal/vitest-context'<br/>→ vitest-context.js (modern)
    else Vitest < 4
        CheckHelper-->>Plugin: false
        Plugin->>Vite: alias '@storybook/addon-vitest/internal/vitest-context'<br/>→ vitest-context-legacy.js
    end
    Note over Plugin,Vite: vitest-context.ts handles<br/>dynamic resolution at runtime
Loading
sequenceDiagram
    participant Module as test-utils.ts
    participant Runtime as Runtime (test execution)
    participant ViContext as vitest-context.ts
    participant Vitest as @vitest/browser or vitest/browser
    
    Module->>Runtime: testStory() called
    Runtime->>Module: need initialGlobals
    Module->>ViContext: dynamically import vitest-context
    ViContext->>Vitest: check Vitest version
    alt Vitest >= 4
        Vitest-->>ViContext: vitest/browser context
    else Vitest < 4
        Vitest-->>ViContext: @vitest/browser/context
    end
    ViContext-->>Module: getInitialGlobals function
    Module->>Module: extract initialGlobals via server.commands
    Module-->>Runtime: pass to composeStory with fallback {}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Attention areas:
    • code/addons/vitest/src/postinstall.ts: Extensive version-aware refactoring with new template selection logic, dependency deduplication, and workspace handling; requires careful verification of template paths and conditional branches for both Vitest 3.x and 4.x paths.
    • code/addons/vitest/src/vitest-plugin/vitest-context.ts: Critical runtime version detection and dynamic import logic; ensure semver branching is correct and error handling is robust.
    • code/addons/vitest/src/vitest-plugin/index.ts: Conditional alias resolution and inclusion logic; verify integration with Vite config and that both vitest-context paths are properly resolved.
    • code/addons/vitest/src/node/vitest-manager.ts: Signature change to isStorybookProject() affecting multiple call sites; verify all references updated correctly.
    • Interdependency between new vitest-context modules and their consumers (test-utils.ts, viewports.ts, index.ts); ensure type casting and error handling are consistent.

Possibly related issues

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “Addon-Vitest: Support Vitest 4” directly reflects the primary purpose of the changeset, which is to update the Storybook Vitest addon for compatibility with Vitest 4, and it does so in a clear and concise manner without extraneous detail.

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Oct 1, 2025

View your CI Pipeline Execution ↗ for commit 10e8b3e

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 44s View ↗

☁️ Nx Cloud last updated this comment at 2025-10-26 11:54:36 UTC

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
code/addons/vitest/src/vitest-plugin/index.ts (1)

281-304: Replace @ts-expect-error with explicit instances support for Vitest 4.
Vitest 4 removes the automatic fallback from browser.name and makes browser.instances required. Rather than suppressing the type error, either cast the config to Vitest’s expected type or include

instances: [{ browser: name }]

to satisfy the types.

code/core/src/test/preview.ts (1)

21-24: Switch default mock cleanup to resetAllMocks().

The default branch currently calls restoreAllMocks(), which only restores spies and leaves automock state intact. To fully reset both spies and automocks between stories, replace restoreAllMocks() with resetAllMocks(), or use clearAllMocks() if only call-history reset is needed.

code/addons/vitest/templates/vitest.config.4.template.ts (1)

10-12: Minor: simplify dirname resolution (optional).

You can drop the __dirname guard and always use fileURLToPath(import.meta.url); Node ESM is standard for config files now. If you keep dual CJS/ESM support, current code is fine.

code/addons/vitest/src/postinstall.ts (2)

541-551: CLI hint: always suggest --project=storybook for consistency.

New installs also create a projects config; recommending vitest --project=storybook avoids accidentally running other projects in mixed setups.

-  const runCommand = rootConfig ? `npx vitest --project=storybook` : `npx vitest`;
+  const runCommand = `npx vitest --project=storybook`;

373-384: Type shim placement OK; consider idempotent write (optional).

You already check existence, but writing at repo root can surprise monorepos. Consider writing next to the config file or guarding with a header comment to detect prior content.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f825cd5 and e475aa6.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (12)
  • code/addons/vitest/package.json (2 hunks)
  • code/addons/vitest/src/node/vitest-manager.ts (2 hunks)
  • code/addons/vitest/src/postinstall.ts (5 hunks)
  • code/addons/vitest/src/vitest-plugin/index.ts (2 hunks)
  • code/addons/vitest/src/vitest-plugin/test-utils.ts (1 hunks)
  • code/addons/vitest/src/vitest-plugin/viewports.ts (1 hunks)
  • code/addons/vitest/templates/vitest.config.3.2.template.ts (1 hunks)
  • code/addons/vitest/templates/vitest.config.4.template.ts (1 hunks)
  • code/addons/vitest/templates/vitest.config.template.ts (1 hunks)
  • code/addons/vitest/templates/vitest.workspace.template.ts (1 hunks)
  • code/core/src/actions/loaders.ts (1 hunks)
  • code/core/src/test/preview.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/addons/vitest/templates/vitest.workspace.template.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/postinstall.ts
  • code/core/src/test/preview.ts
  • code/core/src/actions/loaders.ts
  • code/addons/vitest/templates/vitest.config.3.2.template.ts
  • code/addons/vitest/src/vitest-plugin/viewports.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/vitest/templates/vitest.config.template.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/addons/vitest/templates/vitest.config.4.template.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/addons/vitest/templates/vitest.workspace.template.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/postinstall.ts
  • code/core/src/test/preview.ts
  • code/core/src/actions/loaders.ts
  • code/addons/vitest/templates/vitest.config.3.2.template.ts
  • code/addons/vitest/src/vitest-plugin/viewports.ts
  • code/addons/vitest/src/vitest-plugin/index.ts
  • code/addons/vitest/templates/vitest.config.template.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/addons/vitest/templates/vitest.config.4.template.ts
🧠 Learnings (9)
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/vitest/templates/vitest.workspace.template.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/postinstall.ts
📚 Learning: 2025-09-25T09:21:27.284Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned

Applied to files:

  • code/addons/vitest/templates/vitest.workspace.template.ts
  • code/addons/vitest/templates/vitest.config.3.2.template.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests

Applied to files:

  • code/core/src/test/preview.ts
  • code/core/src/actions/loaders.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without vi.mocked()

Applied to files:

  • code/core/src/actions/loaders.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking without the spy: true option

Applied to files:

  • code/core/src/actions/loaders.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use type-safe mocking with vi.mocked()

Applied to files:

  • code/core/src/actions/loaders.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mocked() to access and implement mock behaviors

Applied to files:

  • code/core/src/actions/loaders.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mocked() to type and access mocked functions

Applied to files:

  • code/core/src/actions/loaders.ts
📚 Learning: 2025-09-25T09:21:27.284Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing

Applied to files:

  • code/addons/vitest/templates/vitest.config.4.template.ts
🧬 Code graph analysis (2)
code/addons/vitest/src/postinstall.ts (1)
code/addons/vitest/src/updateVitestFile.ts (1)
  • loadTemplate (9-16)
code/addons/vitest/templates/vitest.config.4.template.ts (3)
scripts/ecosystem-ci/before-test.js (1)
  • __dirname (15-15)
code/lib/cli-storybook/test/helpers.cjs (1)
  • path (2-2)
code/addons/vitest/src/vitest-plugin/index.ts (1)
  • storybookTest (100-450)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (13)
code/addons/vitest/templates/vitest.config.template.ts (1)

24-29: LGTM: Explicit browser configuration replaces placeholder.

The replacement of BROWSER_CONFIG with an explicit browser configuration object is clear and appropriate for Vitest 4 support. The Playwright provider with Chromium instance is a sensible default.

code/addons/vitest/src/vitest-plugin/viewports.ts (1)

5-5: LGTM: Removed unused import.

The ViewportStyles import has been removed while retaining ViewportMap. This appears to be appropriate cleanup as ViewportStyles is not referenced in the file.

code/addons/vitest/src/vitest-plugin/test-utils.ts (1)

3-3: LGTM: Removed unused import.

The toTestId function has been removed from the import statement. This is appropriate cleanup as the function is not used in the file.

code/addons/vitest/package.json (2)

107-110: LGTM: Peer dependency ranges support both Vitest 3 and 4.

The broadened peer dependency ranges (^3.0.0 || ^4.0.0) provide excellent backward compatibility, allowing users to adopt Vitest 4 at their own pace while maintaining support for Vitest 3.


85-86: Verify Vitest beta stability before production release.

Vitest 4.0 remains in pre-release (latest: v4.0.0-beta.13, published Sep 24, 2025) with no stable 4.0.0 release date announced. Confirm:

  • Is this addon intended for beta/canary distribution only?
  • Should production releases wait for the stable 4.0.0?
  • Has the beta been fully tested with the Storybook integration?
code/addons/vitest/templates/vitest.workspace.template.ts (1)

23-28: LGTM: Explicit browser configuration replaces placeholder.

The replacement of BROWSER_CONFIG with an explicit browser configuration is consistent with the changes in vitest.config.template.ts. The Playwright provider with Chromium is appropriate for Vitest browser testing.

code/core/src/actions/loaders.ts (1)

21-25: LGTM! Clear migration note.

The TODO comment appropriately flags the Vitest 3-specific check for future removal and provides a helpful link to the migration guide.

code/addons/vitest/src/vitest-plugin/index.ts (1)

269-279: LGTM! Clear Vitest 3 compatibility handling.

The conditional inlining of @storybook/addon-vitest is correctly guarded and includes a clear TODO for removal once Vitest 3 support is dropped.

code/addons/vitest/src/node/vitest-manager.ts (2)

167-170: LGTM! Unified module invalidation approach.

The refactored updateLastChanged method now iterates over all Vitest projects to invalidate modules, replacing the previous per-project approach. This is cleaner and aligns with Vitest 4's project handling.


502-504: Ensure TestProject‐only signature – confirm that both globTestSpecifications()’s workspaceSpec.project and entries in this.vitest.projects are actually TestProject (not WorkspaceProject) under both Vitest 3 and 4.

code/addons/vitest/templates/vitest.config.3.2.template.ts (1)

24-29: Approve explicit browser configuration
The browser.instances option is supported since Vitest v3, so this setup is valid for Vitest 3.2.

code/addons/vitest/templates/vitest.config.4.template.ts (1)

14-37: Template shape matches Vitest 4 browser config (provider + instances).

Config uses projects, extends root, and sets Playwright with instances — consistent with Vitest 4 docs. Looks good.

code/addons/vitest/src/postinstall.ts (1)

435-440: Remove unnecessary v4‐template preference
The v3.2 template already includes the browser.instances field, so switching to a v4 template solely for that field isn’t needed.

Likely an incorrect or invalid review comment.

@storybook-app-bot
Copy link

storybook-app-bot bot commented Oct 1, 2025

Package Benchmarks

Commit: 10e8b3e, ran on 26 October 2025 at 11:49:07 UTC

The following packages have significant changes to their size or dependencies:

@storybook/addon-vitest

Before After Difference
Dependency count 6 6 0
Self size 509 KB 578 KB 🚨 +69 KB 🚨
Dependency size 1.53 MB 1.53 MB 🎉 -251 B 🎉
Bundle Size Analyzer Link Link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/addons/vitest/package.json (1)

80-105: Align Vitest peerDependencies with beta & remove duplicate ts-dedent

  • Update all Vitest peer ranges from ^4.0.0 to ^4.0.0-beta.16 so they match your devDependencies.
  • Remove the redundant ts-dedent entry (keep it only under devDependencies).
🧹 Nitpick comments (2)
code/addons/vitest/package.json (2)

74-105: Remove duplicate dependency: ts-dedent is listed twice.

It’s in both dependencies (Line 78) and devDependencies (Line 102). Keep one (likely runtime dependency), remove the other.

-    "ts-dedent": "^2.2.0",

107-112: Add Playwright as an optional peer and pin its version in templates
Declare “playwright” (or “playwright-core”) as an optional peer dependency in code/addons/vitest/package.json (e.g. ^1.52.0) or document it in your docs/postinstall, and update code/addons/vitest/templates to include the pinned Playwright version per repo policy.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a0d302 and 025c031.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • code/addons/vitest/package.json (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/addons/vitest/package.json (1)

117-119: Optional peer meta for @vitest/browser-playwright: LGTM.

Prevents noisy peer warnings for users not using browser mode.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
code/addons/vitest/package.json (2)

117-119: Optional peer for @vitest/browser-playwright is correct — add a migration note.

Good call marking it optional. Please document that Vitest 4 browser mode requires installing @vitest/browser-playwright (and any Playwright prerequisites), while Vitest 3 users can keep @vitest/browser.

Happy to draft a short “Vitest 3 -> 4” migration note for the addon README.


107-112: Simplify 4.x prerelease-inclusive ranges
Replace each ^4.0.0 || ^4.0.0-beta in code/addons/vitest/package.json (lines 107–112) with >=4.0.0-0 <5.0.0 to cover all 4.x prereleases and stable releases.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 025c031 and 3bd59fc.

📒 Files selected for processing (1)
  • code/addons/vitest/package.json (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/addons/vitest/package.json (1)

85-86: Vitest 4 beta versions verified on npm
All 4.0.0-beta.16 packages exist. Note that ^4.0.0-beta.16 will not resolve to the stable 4.0.0—plan an explicit bump to GA when it’s released.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
code/addons/vitest/package.json (1)

100-105: Remove duplicate dependency ts-dedent from devDependencies

ts-dedent exists in both dependencies (Line 78) and devDependencies (Line 102). Keep it only once (dependencies).

Apply this diff:

   "tinyglobby": "^0.2.10",
   "tree-kill": "^1.2.2",
-  "ts-dedent": "^2.2.0",
   "typescript": "^5.8.3",
   "vitest": "^4.0.0-beta.16"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd59fc and 9ed6fb8.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • code/addons/vitest/package.json (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (4)
code/addons/vitest/package.json (4)

85-86: Dev deps update to Vitest 4 path looks good

Switch to @vitest/browser-playwright and @vitest/runner v4 beta aligns with the new provider.


107-112: Confirm support expectations for @vitest/browser in v4

If v4 usage is exclusively via @vitest/browser-playwright, consider narrowing @vitest/browser to ^3.0.0 to avoid conflicting installs with two browser providers. If you truly support @vitest/browser@4, please confirm the runtime selection logic.

Option if not supported in v4:

-    "@vitest/browser": "^3.0.0 || ^4.0.0 || ^4.0.0-beta",
+    "@vitest/browser": "^3.0.0",

117-119: Optional peer meta for @vitest/browser-playwright looks right

Marking it optional avoids noisy warnings while postinstall handles guidance.


107-109: Postinstall and templates already enforce one-of peer dependency The postinstall script auto-installs the correct provider (@vitest/browser on v3, @vitest/browser-playwright on v4), and all templates default to the appropriate provider.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
code/addons/vitest/src/node/vitest-manager.ts (1)

167-182: LGTM! Cross-version compatibility handled well.

The iteration over projects with conditional checks for browser, vite, and server fields correctly handles both Vitest 2 and 3+ structures. The @ts-expect-error directive appropriately suppresses TypeScript errors for the version-specific server field.

Minor consistency note: Line 171 uses explicit (mod: any) typing while line 175 infers the type. Consider adding a brief comment on line 171 explaining why any is necessary (e.g., TypeScript cannot properly type server.moduleGraph due to its version-specific nature):

       if (server) {
         const serverMods = server.moduleGraph.getModulesByFile(filepath);
-        serverMods?.forEach((mod: any) => server.moduleGraph.invalidateModule(mod));
+        // Type is `any` because TypeScript cannot infer the exact type from version-specific `server.moduleGraph`
+        serverMods?.forEach((mod: any) => server.moduleGraph.invalidateModule(mod));
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d0ec4c and c7a2581.

📒 Files selected for processing (1)
  • code/addons/vitest/src/node/vitest-manager.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/addons/vitest/src/node/vitest-manager.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/addons/vitest/src/node/vitest-manager.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/vitest/src/node/vitest-manager.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/addons/vitest/src/node/vitest-manager.ts (1)

513-515: LGTM! Signature correctly narrowed.

The method signature change from TestProject | WorkspaceProject to TestProject aligns with the Vitest 3+ API structure. All call sites (lines 347, 358, 374) remain type-safe with this change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

🧹 Nitpick comments (16)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/vitest.setup.ts (1)

1-8: Consider whether the console.log is needed.

The setup correctly wires Storybook annotations with Vitest. The console.log(getString()) on Line 8 may be intentional for verifying that setup file dependencies are loaded correctly, or it could be a debug artifact. If it's for verification purposes, consider adding a comment explaining its purpose.

If the console.log is for debugging only, apply this diff:

 setProjectAnnotations([addonA11yAnnotations, projectAnnotations]);
-
-console.log(getString());

If it's intentional for verification, add a comment:

 setProjectAnnotations([addonA11yAnnotations, projectAnnotations]);
 
+// Log to verify setup file dependencies are loaded correctly
 console.log(getString());
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview.tsx (1)

4-4: Consider removing or explaining the console log.

This debug statement will execute every time the preview configuration loads. If this is intentional for testing purposes, consider adding a comment explaining why. Otherwise, remove it.

-console.log('preview file is called!');
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/main.ts (2)

15-20: Consider documenting the red border CSS.

The injected CSS adds a red border to the body element, which appears to be a testing artifact. Add a comment explaining its purpose to avoid confusion.

+ // Red border for visual testing verification
  previewHead: (head = "") => `${head}
  <style>
    body {
      border: 1px solid red;
    }
  </style>`,

22-37: Simplify redundant optimizeDeps spread.

Line 27 spreads config.optimizeDeps?.include into a new array without modification, which is redundant. You can simplify this.

  viteFinal: (config) => {
    return {
      ...config,
-     optimizeDeps: {
-       ...config.optimizeDeps,
-       include: [...(config.optimizeDeps?.include || [])],
-     },
      resolve: {
        ...config.resolve,
        alias: {
          ...config.resolve?.alias,
          "test-alias": join(import.meta.dirname, "aliased.ts"),
        },
      },
    };
  },
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.node.json (1)

1-11: Tighten tsconfig.node.json for config-only use

  • Add top-level "$schema": "https://json.schemastore.org/tsconfig"
  • Set compilerOptions.noEmit to true
  • Add compilerOptions.types = ["node"]
  • Optionally add compilerOptions.esModuleInterop = true
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.json (2)

23-24: Split browser vs Node test configs to avoid type pollution.

Including e2e-tests here (with DOM libs) can blur Node vs browser types. Prefer: keep this tsconfig for stories/browser; move e2e to tsconfig.node.json with Node/Playwright/Vitest types.

Proposed change:

-  "include": ["stories", "e2e-tests"],
+  "include": ["stories"],

And ensure tsconfig.node.json contains:

{
  "compilerOptions": {
    "composite": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "noEmit": true,
    "types": ["node", "playwright", "vitest/globals"]
  },
  "include": ["e2e-tests", "vitest.config.*", "vite.config.*", "playwright.config.*"]
}

Please confirm tsconfig.node.json already sets these types; if not, we can amend it. Based on learnings.


12-16: Add Vite client types for better DX.

Include vite/client to get import.meta.env and asset module typings.

   "isolatedModules": true,
   "noEmit": true,
   "jsx": "react-jsx",
+  "types": ["vite/client"]
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx (1)

66-66: Inconsistent quote style.

Line 66 uses double quotes while the rest of the file uses single quotes (lines 57, 75, etc.). Maintain consistency.

Apply this diff:

-    children: "foo",
+    children: 'foo',
.circleci/src/jobs/e2e-ui-vitest-3.yml (2)

11-16: Drop redundant Yarn immutability toggles

You’re using both --no-immutable and YARN_ENABLE_IMMUTABLE_INSTALLS=false. One is enough. Prefer the CLI flag for clarity.

-      command: yarn install --no-immutable
-      working_directory: test-storybooks/portable-stories-kitchen-sink/react-vitest-3
-      environment:
-        YARN_ENABLE_IMMUTABLE_INSTALLS: false
+      command: yarn install --no-immutable
+      working_directory: test-storybooks/portable-stories-kitchen-sink/react-vitest-3

20-24: Optional: upload Playwright traces/videos for debugging

If generated, also store playwright-report or traces/videos to aid triage.

   - store_artifacts:
       path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results/
       destination: playwright
+  - store_artifacts:
+      path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-report
+      destination: playwright-report
+  - store_artifacts:
+      path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results/traces
+      destination: playwright-traces
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts (1)

6-6: Unify host with Playwright webServer to avoid cross-origin quirks

Use 127.0.0.1 (matches config) to keep cookies/storage on the same origin as the server.

-const STORYBOOK_URL = "http://localhost:6006";
+const STORYBOOK_URL = "http://127.0.0.1:6006";
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts (1)

5-5: Unify host with Playwright webServer

Match 127.0.0.1 to avoid localhost vs 127.0.0.1 origin differences.

-const STORYBOOK_URL = "http://localhost:6006";
+const STORYBOOK_URL = "http://127.0.0.1:6006";
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts (2)

8-8: Unify host with Playwright webServer

Switch to 127.0.0.1 to match the config URL.

-const STORYBOOK_URL = "http://localhost:6006";
+const STORYBOOK_URL = "http://127.0.0.1:6006";

141-143: Drop redundant await on page.locator(...)

locator() is synchronous; remove await for clarity.

-    const testingModuleDescription = await page.locator(
+    const testingModuleDescription = page.locator(
       "#testing-module-description"
     );
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js (1)

6-10: Make path resolution robust and strengthen replacement

Use __dirname to avoid CWD sensitivity and a regex for safer replacement.

-const testStoryPath = path.resolve("stories/AddonTest.stories.tsx");
+const testStoryPath = path.resolve(__dirname, "stories", "AddonTest.stories.tsx");
@@
-fs.writeFileSync(testStoryPath, storyContent.replace("forceFailure: true", "forceFailure: false"));
+fs.writeFileSync(
+  testStoryPath,
+  storyContent.replace(/forceFailure:\s*true/g, "forceFailure: false")
+);
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx (1)

3-5: Set button type to avoid unintended submit in form contexts

Not required here, but safer generally.

-export const Component = () => {
-  return <button>{getButtonString()}</button>;
-};
+export const Component = () => {
+  return <button type="button">{getButtonString()}</button>;
+};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7a2581 and 081a13e.

⛔ Files ignored due to path filters (2)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • test-storybooks/portable-stories-kitchen-sink/react/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (38)
  • .circleci/README.md (1 hunks)
  • .circleci/src/jobs/e2e-ui-vitest-3.yml (1 hunks)
  • .circleci/src/workflows/daily.yml (1 hunks)
  • .circleci/src/workflows/merged.yml (1 hunks)
  • .circleci/src/workflows/normal.yml (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.eslintrc.cjs (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.gitignore (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/aliased.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/get-decorator-string.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/main.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview-head.html (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/setup-file-dependency.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/test-static-dirs/static.js (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/vitest.setup.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.yarnrc.yml (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/package.json (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/button.css (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.json (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.node.json (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vite.config.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vitest.workspace.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/package.json (2 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/svelte/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vitest.workspace.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.yarnrc.yml
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview-head.html
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.gitignore
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vite.config.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vite.config.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts
test-storybooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain test configurations and assets under test-storybooks/ for Storybook testing

Files:

  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vite.config.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.json
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js
  • test-storybooks/portable-stories-kitchen-sink/svelte/package.json
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/package.json
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.node.json
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/button.css
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts
  • test-storybooks/portable-stories-kitchen-sink/react/package.json
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned
📚 Learning: 2025-09-25T09:21:27.284Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing

Applied to files:

  • .circleci/README.md
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/main.ts
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts
  • test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts
📚 Learning: 2025-09-25T09:21:27.284Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned

Applied to files:

  • .circleci/src/jobs/e2e-ui-vitest-3.yml
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview.tsx
🧬 Code graph analysis (13)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx (1)
code/core/src/csf/csf-factories.ts (1)
  • Meta (77-96)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx (1)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts (1)
  • getButtonString (1-3)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts (1)
code/e2e-tests/util.ts (1)
  • SbPage (8-255)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/vitest.setup.ts (1)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/setup-file-dependency.ts (1)
  • getString (1-3)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts (1)
code/e2e-tests/util.ts (1)
  • SbPage (8-255)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx (1)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx (2)
  • Button (30-44)
  • ButtonProps (4-25)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx (1)
code/core/src/csf/csf-factories.ts (1)
  • Meta (77-96)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx (4)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx (1)
  • Component (3-5)
code/core/src/test/index.ts (1)
  • instrument (24-44)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/test-static-dirs/static.js (2)
  • staticFunction (3-3)
  • staticFunction (3-3)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/aliased.ts (1)
  • aliasedFunction (4-4)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts (1)
code/e2e-tests/util.ts (1)
  • SbPage (8-255)
test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts (1)
code/addons/vitest/src/vitest-plugin/index.ts (1)
  • storybookTest (100-448)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview.tsx (1)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/get-decorator-string.ts (1)
  • getDecoratorString (1-3)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx (1)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx (2)
  • Button (30-44)
  • ButtonProps (4-25)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts (2)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js (1)
  • path (4-4)
scripts/ecosystem-ci/before-test.js (1)
  • __dirname (15-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (31)
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.eslintrc.cjs (1)

1-14: LGTM! Standard ESLint configuration for React + TypeScript + Storybook.

The configuration is appropriate for a modern React + TypeScript + Storybook project with Vitest. All settings—including the react-refresh rule for HMR, the parser, plugins, and extended configs—are standard and correct.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/test-static-dirs/static.js (1)

1-3: LGTM! Minimal test helper for staticDirs verification.

The implementation is appropriate for its purpose—a simple smoke test to verify that files from staticDirs can be loaded in Vitest tests.

test-storybooks/portable-stories-kitchen-sink/react/package.json (1)

78-81: LGTM! Vitest 4 beta upgrade is consistent.

The upgrade to Vitest 4.0.0-beta.17 across all related packages (@vitest/browser, @vitest/browser-playwright, @vitest/coverage-v8, @vitest/ui, and vitest core) maintains version consistency. The addition of @vitest/browser-playwright aligns with the PR's objective to support Vitest 4 with Playwright browser integration.

Also applies to: 93-93

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/get-decorator-string.ts (1)

1-3: LGTM!

Simple test helper function with clear purpose.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx (1)

1-22: LGTM!

Test story with intentional failure is properly tagged with 'fail-on-purpose' for test validation purposes.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vite.config.ts (1)

1-7: LGTM!

Standard Vite configuration with React plugin, appropriate for the test storybook setup.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/setup-file-dependency.ts (1)

1-3: LGTM!

Test helper function to verify setup file dependency resolution.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/aliased.ts (1)

1-4: LGTM!

Well-documented test helper for verifying Vite alias resolution in the Vitest environment.

test-storybooks/portable-stories-kitchen-sink/svelte/package.json (1)

69-69: Confirm need for @vitest/browser-playwright in Svelte tests
No vitest.config or test scripts reference browser/Playwright in the Svelte subpackage. If you don’t require browser-mode or E2E testing, adding @vitest/browser-playwright isn’t necessary. Otherwise, install it and update your vitest.config accordingly.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview.tsx (1)

6-29: LGTM!

The preview configuration is well-structured with appropriate decorators, initial globals, and global types for locale switching. The decorator implementation correctly wraps stories with test-friendly attributes.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/package.json (3)

15-15: LGTM! Playwright version correctly pinned.

The Playwright version is correctly pinned to 1.52.0 in resolutions and devDependencies, aligning with the project's E2E testing standards.

Based on learnings.

Also applies to: 51-51, 58-58


71-73: Confirm Vitest 3 usage in a Vitest 4 support PR.

This test setup uses Vitest 3.x (vitest: "^3.2.4" and related @vitest/* packages), while the PR title indicates "Vitest 4 Support". Verify whether this is intentional (e.g., to maintain backward compatibility testing alongside Vitest 4) or if these versions should be updated.

Also applies to: 82-82


9-9: playwright-e2e.config.ts presence verified Verified that the referenced configuration file exists; no further action needed.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/main.ts (2)

1-11: LGTM!

The configuration structure is appropriate for a test Storybook setup, with proper story patterns, addon registration, framework configuration, and external refs.

Also applies to: 38-50


33-33: Engines.node specifies ≥22.0.0, satisfying import.meta.dirname support—no changes required.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx (4)

1-1: LGTM!

Import statement is correct and follows Storybook conventions.


3-13: LGTM!

The error-throwing helpers are correctly implemented:

  • unhandledRejection is intentionally async to create a rejected promise when it throws
  • unhandledError throws synchronously for testing unhandled errors
  • throwError is a simple helper for consistency

31-46: LGTM!

Story definitions follow Storybook conventions and cover the three test scenarios:

  • UnhandledError for testing unhandled synchronous errors
  • UnhandledRejection for testing unhandled promise rejections
  • Success as a control case

14-30: Tests dynamically override forceFailure; default stories are correct
E2E and Vitest scripts set forceFailure to true at runtime, so having it default to false in the story is intentional.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.json (1)

10-11: moduleResolution "bundler" requirement satisfied: this project pins TypeScript to ^5.8.3 (≥5.0.0).

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/button.css (1)

1-30: LGTM!

The CSS follows a clear BEM-like naming convention with well-defined modifiers for button variants and sizes.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx (1)

1-19: LGTM!

The story file correctly uses CSF3 format with TypeScript types. The '!test' tag on line 9 appropriately excludes this story from test runs, which appears intentional for testing the Vitest integration's filtering behavior.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx (1)

1-1: Import path is correct 'storybook/test' is the configured internal alias for the test utilities; no change required.

test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts (3)

1-4: LGTM! Imports are correctly aligned with Vitest 4.

The imports correctly use vitest/config for defineConfig (Vitest 4 pattern) and include the necessary plugins for Storybook test integration with Playwright browser support.


8-19: LGTM! Clean conditional plugin configuration.

The conditional logic for excluding the "fail-on-purpose" tag based on the environment variable is well-structured and allows for flexible test execution.


23-29: Verify if disabling the web optimizer is necessary.

Setting deps.optimizer.web.enabled: false disables Vite's dependency optimization for web targets. While this may be intentional for Storybook test compatibility, it could impact performance. Please confirm whether this configuration is required or if it can be removed.

If this is a known requirement for Storybook tests with Vitest 4, consider adding a brief comment explaining why it's disabled.

.circleci/README.md (1)

56-56: Docs addition looks good

The new e2e-ui-vitest3 job is documented and matches workflow keys.

.circleci/src/workflows/normal.yml (1)

65-67: LGTM: job added with correct dependency

e2e-ui-vitest3 is correctly gated on build, mirroring e2e-ui.

.circleci/src/workflows/merged.yml (1)

66-68: LGTM: merged workflow parity

e2e-ui-vitest3 added with the proper build dependency.

.circleci/src/workflows/daily.yml (1)

66-68: LGTM: daily workflow parity

e2e-ui-vitest3 added and depends on build; consistent across workflows.

test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts (1)

1-3: LGTM

Simple, correct utility. No issues.

Comment on lines 1 to 3
executor:
name: sb_playwright
class: medium
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify Playwright version = 1.52.0 per policy

Ensure the test project uses Playwright 1.52.0 and config is aligned with our standard.

Based on learnings

Also applies to: 17-19


🏁 Script executed:

#!/bin/bash
# Check declared Playwright deps in the Vitest 3 test project
set -euo pipefail
proj="test-storybooks/portable-stories-kitchen-sink/react-vitest-3"
if [ -f "$proj/package.json" ]; then
  echo "Deps in $proj/package.json:"
  jq -r '.dependencies, .devDependencies | to_entries[]? | select(.key|test("playwright|@playwright/test")) | "\(.key): \(.value)"' "$proj/package.json" || true
else
  echo "Missing $proj/package.json" >&2
fi

# Show any playwright config files present for a quick audit
echo
echo "Playwright config files:"
fd -a --max-results 50 -t f -E node_modules -S 'playwright*.config.*' "$proj" || true

Length of output: 305


🏁 Script executed:

#!/bin/bash
proj="test-storybooks/portable-stories-kitchen-sink/react-vitest-3"
echo "Searching for Playwright config files in $proj:"
find "$proj" -type f -iregex '.*playwright\.config\..*' || true

Length of output: 102


Add standard Playwright config for Vitest 3 E2E

  • @playwright/test is pinned to v1.52.0 in test-storybooks/portable-stories-kitchen-sink/react-vitest-3/package.json – OK.
  • No playwright.config.* file in test-storybooks/portable-stories-kitchen-sink/react-vitest-3; add the standard playwright.config.ts (or reference the root config) to align with policy.

Comment on lines 20 to 24
- store_test_results:
path: test-results
- store_artifacts:
path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results/
destination: playwright
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix test results path: CircleCI won’t find them at repo root

Tests run in test-storybooks/.../react-vitest-3, but store_test_results points to test-results at repo root. Align paths so JUnit results upload correctly.

Apply:

-  - store_test_results:
-      path: test-results
+  - store_test_results:
+      path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- store_test_results:
path: test-results
- store_artifacts:
path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results/
destination: playwright
- store_test_results:
path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results
- store_artifacts:
path: test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results/
destination: playwright
🤖 Prompt for AI Agents
In .circleci/src/jobs/e2e-ui-vitest-3.yml around lines 20 to 24, the
store_test_results step points to test-results at the repo root but the Vitest
JUnit output is written under
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results;
update the store_test_results path to the same directory used by store_artifacts
(test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results) so
CircleCI can find and upload the JUnit results.

Comment on lines 137 to 139
if ((await testStoryElement.getAttribute("aria-expanded")) !== "true") {
testStoryElement.click();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing await on click may cause flake

Ensure the expand action completes before proceeding.

-    if ((await testStoryElement.getAttribute("aria-expanded")) !== "true") {
-      testStoryElement.click();
-    }
+    if ((await testStoryElement.getAttribute("aria-expanded")) !== "true") {
+      await testStoryElement.click();
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ((await testStoryElement.getAttribute("aria-expanded")) !== "true") {
testStoryElement.click();
}
if ((await testStoryElement.getAttribute("aria-expanded")) !== "true") {
await testStoryElement.click();
}
🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts
around lines 137 to 139, the click call is missing an await which can cause
flaky tests; change the code to await the click so the expand action completes
before proceeding and optionally await a short assertion/wait until
testStoryElement.getAttribute("aria-expanded") === "true" to ensure the element
finished expanding.

Comment on lines 1 to 122
import { expect, test } from "@playwright/test";

import { SbPage } from "../../../../code/e2e-tests/util";

const STORYBOOK_URL = "http://localhost:6006";

test.describe("composition", () => {
// the composed storybook can be slow to load, so we need to increase the timeout
test.describe.configure({ mode: "serial", timeout: 60000, retries: 2 });
test("should filter and render composed stories", async ({ page }) => {
await page.goto(STORYBOOK_URL);
await new SbPage(page, expect).waitUntilLoaded();

// Expect that composed Storybooks are visible
await expect(page.getByTitle("Storybook 8.0.0")).toBeVisible();
await expect(page.getByTitle("Storybook 7.6.18")).toBeVisible();

// Expect composed stories to be available in the sidebar
await page.locator('[id="storybook\\@8\\.0\\.0_components-badge"]').click();
await expect(
page.locator('[id="storybook\\@8\\.0\\.0_components-badge--default"]')
).toBeVisible();

await page
.locator('[id="storybook\\@7\\.6\\.18_components-badge"]')
.click();
await expect(
page
.locator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
.contentFrame()
.locator("#storybook-root")
.getByText("Default")
).toBeVisible({ timeout: 15000 });

// Expect composed stories `to be available in the search
await page.getByPlaceholder("Find components").fill("Button primary");
await expect(
page.getByRole("option", {
name: "Primary Storybook 7.6.18 / @components / Button",
})
).toBeVisible();

const buttonStory = page.getByRole("option", {
name: "Primary Storybook 8.0.0 / @blocks / examples / Button",
});
await expect(buttonStory).toBeVisible();
await buttonStory.click();

// Note: this could potentially be flaky due to it accessing a hosted Storybook
await expect(
page
.locator('iframe[title="storybook-ref-storybook\\@8\\.0\\.0"]')
.contentFrame()
.getByRole("button")
).toBeVisible({ timeout: 15000 });
});

test("should filter and render composed stories on mobile", async ({
page,
}) => {
page.setViewportSize({ width: 320, height: 800 });
await page.goto(STORYBOOK_URL);
await new SbPage(page, expect).waitUntilLoaded();

await page.click('button[aria-label="Open navigation menu"]');

// scroll down to the bottom of the element getByText('Skip to canvasStorybookSearch')

await page.getByTitle("Storybook 7.6.18").scrollIntoViewIfNeeded();

// Expect that composed Storybooks are visible
await expect(page.getByTitle("Storybook 8.0.0")).toBeVisible();
await expect(page.getByTitle("Storybook 7.6.18")).toBeVisible();

// Expect composed stories to be available in the sidebar
await expect(
page.locator('[id="storybook\\@8\\.0\\.0_components-badge"]')
).toBeVisible();
await page.locator('[id="storybook\\@8\\.0\\.0_components-badge"]').click();
await expect(
page.locator('[id="storybook\\@8\\.0\\.0_components-badge--default"]')
).toBeVisible();

await page
.locator('[id="storybook\\@7\\.6\\.18_components-badge"]')
.click();
await page
.locator('[id="storybook\\@7\\.6\\.18_components-badge--default"]')
.click();
await expect(
page
.locator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
.contentFrame()
.locator("#storybook-root")
.getByText("Default")
).toBeVisible({ timeout: 15000 });

await page.click('button[aria-label="Open navigation menu"]');

// Expect composed stories `to be available in the search
await page.getByPlaceholder("Find components").fill("Button primary");
await expect(
page.getByRole("option", {
name: "Primary Storybook 7.6.18 / @components / Button",
})
).toBeVisible();

const buttonStory = page.getByRole("option", {
name: "Primary Storybook 8.0.0 / @blocks / examples / Button",
});
await expect(buttonStory).toBeVisible();
await buttonStory.click();

// Note: this could potentially be flaky due to it accessing a hosted Storybook
await expect(
page
.locator('iframe[title="storybook-ref-storybook\\@8\\.0\\.0"]')
.contentFrame()
.getByRole("button")
).toBeVisible({ timeout: 15000 });
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Repo-wide check for contentFrame() misuse

Scan for other places chaining contentFrame() without awaiting and replace with frameLocator().


🏁 Script executed:

#!/bin/bash
# Find chained contentFrame() usages that likely need frameLocator()
rg -nP -C2 --type=ts 'contentFrame\(\)\s*\.\s*(locator|getBy\w+)\s*\('

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any contentFrame() calls across the repository
rg -nP 'contentFrame\(\)' -n

Length of output: 909


Use frameLocator() instead of chaining contentFrame()
Replace all .contentFrame()… chains in test-storybooks/portable-stories-kitchen-sink/{react,react-vitest-3}/e2e-tests/composition.spec.ts with page.frameLocator(iframeSelector).locator(…) to ensure proper waiting.

🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts
lines 1-122, multiple places chain
.locator('iframe[...]').contentFrame().locator(...) or
.contentFrame().getByRole(...); replace each chain with
page.frameLocator('iframe[...]').locator(...) (or
page.frameLocator('iframe[...]').getByRole(...)) so Playwright waits for the
frame and its elements correctly; keep the existing awaits and timeout options
when calling toBeVisible() and click() so behavior and timeouts remain
unchanged.

Comment on lines 24 to 33
await page
.locator('[id="storybook\\@7\\.6\\.18_components-badge"]')
.click();
await expect(
page
.locator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
.contentFrame()
.locator("#storybook-root")
.getByText("Default")
).toBeVisible({ timeout: 15000 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Incorrect chaining of contentFrame(); use frameLocator()

contentFrame() returns a Promise<Frame|null>; chaining .locator() on it is invalid and will fail TS/type-checks. Use frameLocator() instead.

-    await expect(
-      page
-        .locator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
-        .contentFrame()
-        .locator("#storybook-root")
-        .getByText("Default")
-    ).toBeVisible({ timeout: 15000 });
+    await expect(
+      page
+        .frameLocator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
+        .locator("#storybook-root")
+        .getByText("Default")
+    ).toBeVisible({ timeout: 15000 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await page
.locator('[id="storybook\\@7\\.6\\.18_components-badge"]')
.click();
await expect(
page
.locator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
.contentFrame()
.locator("#storybook-root")
.getByText("Default")
).toBeVisible({ timeout: 15000 });
await page
.locator('[id="storybook\\@7\\.6\\.18_components-badge"]')
.click();
await expect(
page
.frameLocator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]')
.locator("#storybook-root")
.getByText("Default")
).toBeVisible({ timeout: 15000 });
🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts
around lines 24 to 33, the test incorrectly chains .locator() off contentFrame()
(contentFrame() returns Promise<Frame|null> and cannot be chained); replace the
contentFrame() usage with a frameLocator targeting the iframe (e.g., use
page.frameLocator('iframe[title="storybook-ref-storybook\\@7\\.6\\.18"]').locator("#storybook-root").getByText("Default"))
so locators are used on the FrameLocator API and the TypeScript/type errors are
resolved.

Comment on lines 21 to 30
reporter: [
["line"],
[
"junit",
{
embedAnnotationsAsProperties: true,
outputFile: path.join(__dirname, "..", "..", "..", "test-results"),
},
],
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

JUnit reporter outputFile should be a file path (and avoid __dirname in TS/ESM)

Currently points to a directory and relies on __dirname. Use a concrete file name relative to the project.

   reporter: [
     ["line"],
     [
       "junit",
       {
         embedAnnotationsAsProperties: true,
-        outputFile: path.join(__dirname, "..", "..", "..", "test-results"),
+        outputFile: path.join("test-results", "junit.xml"),
       },
     ],
   ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reporter: [
["line"],
[
"junit",
{
embedAnnotationsAsProperties: true,
outputFile: path.join(__dirname, "..", "..", "..", "test-results"),
},
],
],
reporter: [
["line"],
[
"junit",
{
embedAnnotationsAsProperties: true,
outputFile: path.join("test-results", "junit.xml"),
},
],
],
🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts
around lines 21 to 30, the JUnit reporter's outputFile is currently pointing to
a directory and uses __dirname (which is problematic in TS/ESM); change it to a
concrete file path (e.g., "test-results/junit.xml" or use
path.join(process.cwd(), "test-results", "junit.xml")) so the reporter writes to
a file, and remove usage of __dirname in favor of process.cwd() or a relative
string.

Comment on lines 11 to 14
const meta = {
title: 'Addons/Group/Test',
component: Component,
} as Meta<typeof Component>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Fix story args typing; avoid as cast with satisfies and declare forceFailure

args.forceFailure is used in plays, but the component has no props, so args type is {}. This will trip strict TS. Declare the arg in meta and use satisfies for safer typing.

As per coding guidelines (prefer precise typings, avoid casts), apply:

-const meta = {
-  title: 'Addons/Group/Test',
-  component: Component,
-} as Meta<typeof Component>;
+const meta = {
+  title: 'Addons/Group/Test',
+  component: Component,
+  // make `forceFailure` a known arg for typed access in play functions
+  args: { forceFailure: false },
+} satisfies Meta<typeof Component>;

Optional: you can then drop the redundant args in ExpectedFailure, or keep it to be explicit—both are fine.


#!/usr/bin/env bash
file="test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx"

echo "=== Story File Head (1–200) ==="
sed -n '1,200p' "$file"

echo
echo "=== Imports ==="
rg -n '^import' -C0 "$file"

echo
echo "=== play Usage ==="
rg -n 'play:' -C3 "$file"

echo
echo "=== args Usage ==="
rg -n 'forceFailure' -C3 "$file"

#!/usr/bin/env bash
file="test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx"

echo "=== Meta Definition ==="
rg -n -C2 'Meta<.*Component>' "$file"

echo
echo "=== args in Meta ==="
rg -n 'args\s*:' -C2 "$file"

echo
echo "=== play functions ==="
rg -n 'play\s*:' -C3 "$file"

echo
echo "=== forceFailure usage ==="
rg -n 'forceFailure' -C3 "$file"

🏁 Script executed:

#!/usr/bin/env bash
set -e

file="test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx"

echo "=== Meta Definition and Casting ==="
rg -n -C1 'Meta<.*Component>' "$file" || echo "No Meta<> matches"
rg -n 'as Meta<' "$file" || echo "No `as Meta` cast found"

echo
echo "=== args in Meta ==="
rg -n 'args\s*:' -C2 "$file" || echo "No args declaration in meta"

echo
echo "=== play functions ==="
rg -n -C2 'play\s*:' "$file" || echo "No play functions found"

echo
echo "=== forceFailure Usage ==="
rg -n -C2 'forceFailure' "$file" || echo "No forceFailure references"

echo
echo "=== Component Import Line ==="
import_line=$(rg -m1 '^import .*Component' "$file" || echo "")
echo "${import_line:-No import of Component found}"

component_path=$(echo "$import_line" | sed -E "s/.*from ['\"](.+)['\"].*/\1/")
if [ -n "$component_path" ]; then
  for ext in tsx js; do
    if [ -f "${component_path}.${ext}" ]; then
      echo
      echo "=== Component File: ${component_path}.${ext} (head) ==="
      sed -n '1,50p' "${component_path}.${ext}"
      break
    fi
  done
fi

Length of output: 1974


#!/usr/bin/env bash
set -e

dir="test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories"
echo "=== Locate Component File ==="
find "$dir" -maxdepth 1 -type f -name 'AddonTest.tsx' -print || echo "Component file not found"

echo
file="$dir/AddonTest.tsx"
if [ -f "$file" ]; then
  echo "=== Component File Head (1–200) ==="
  sed -n '1,200p' "$file"
else
  echo "Skipping inspection; file missing"
fi

🏁 Script executed:

#!/usr/bin/env bash
file="test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx"
if [ -f "$file" ]; then
  echo "=== AddonTest.tsx (1–200) ==="
  sed -n '1,200p' "$file"
else
  echo "AddonTest.tsx not found at expected path"
fi

Length of output: 168


#!/usr/bin/env bash
file="test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx"
echo "=== AddonTest.stories.tsx (1–20) ==="
sed -n '1,20p' "$file"

Use satisfies and declare forceFailure in meta

Switch from an as cast to satisfies and add a default args entry so args.forceFailure is correctly typed:

-const meta = {
-  title: 'Addons/Group/Test',
-  component: Component,
-} as Meta<typeof Component>;
+const meta = {
+  title: 'Addons/Group/Test',
+  component: Component,
+  args: { forceFailure: false },
+} satisfies Meta<typeof Component>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const meta = {
title: 'Addons/Group/Test',
component: Component,
} as Meta<typeof Component>;
const meta = {
title: 'Addons/Group/Test',
component: Component,
args: { forceFailure: false },
} satisfies Meta<typeof Component>;
🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx
around lines 11 to 14, replace the TypeScript "as Meta<typeof Component>" cast
with the "satisfies Meta<typeof Component>" form and add a default args object
that includes forceFailure (e.g. args: { forceFailure: false }) so
args.forceFailure is correctly typed; ensure the meta object still exports
default and any existing references to meta.args remain consistent with the new
property.

Comment on lines 88 to 113
const mockFn = fn();
export const WithLoader: CSF3Story<{ mockFn: (val: string) => string }> = {
args: {
mockFn,
},
loaders: [
async () => {
mockFn.mockReturnValueOnce('mockFn return value');
return {
value: 'loaded data',
};
},
],
render: (args, { loaded }) => {
const data = args.mockFn('render');
return (
<div>
<div data-testid="loaded-data">{loaded.value}</div>
<div data-testid="mock-data">{String(data)}</div>
</div>
);
},
play: async () => {
expect(mockFn).toHaveBeenCalledWith('render');
},
}; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential test isolation issue with module-level mock.

The mockFn defined at module scope (line 88) is shared across test runs. If Vitest doesn't automatically reset mocks between tests, this could lead to state leakage where one test's mock setup affects another.

Consider moving the mock initialization inside the story's loaders or ensuring proper cleanup:

-const mockFn = fn();
 export const WithLoader: CSF3Story<{ mockFn: (val: string) => string }> = {
-  args: {
-    mockFn,
-  },
   loaders: [
     async () => {
+      const mockFn = fn();
       mockFn.mockReturnValueOnce('mockFn return value');
       return {
+        mockFn,
         value: 'loaded data',
       };
     },
   ],

Alternatively, if the current approach is intentional for testing shared mock behavior, add a comment explaining why the mock is at module scope.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx
around lines 88 to 113, the module-level mockFn is shared across test runs which
can cause state leakage; move the mock initialization into the story (e.g.,
create the mock inside the loaders or render function) or explicitly reset it at
the start of the loader (call mockFn.mockReset()/mockClear() before configuring
mockReturnValueOnce), or if intentional, add a comment explaining why a
module-scoped mock is required for this story.

export const Button: React.FC<ButtonProps> = (props) => {
const { primary = false, size = 'medium', backgroundColor, children, ...otherProps } = props;
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
console.log({props})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove debug console.log statement.

The console.log adds noise to test output and serves no functional purpose. Even in test fixtures, avoid leaving debug statements in committed code.

Apply this diff:

-  console.log({props})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log({props})
🤖 Prompt for AI Agents
In
test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx
around line 33, there is a debug console.log({props}) that should be removed;
delete this console.log statement so the test fixture no longer emits noisy
debug output and commit the change.

Comment on lines 30 to 42
browser: {
enabled: true,
provider: playwright({}),
headless: true,
instances: [
{
browser: "chromium",
},
],
},
setupFiles: ["./.storybook/vitest.setup.ts"],
environment: "jsdom",
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Conflicting environment configuration detected.

Setting both browser.enabled: true (Line 31) and environment: "jsdom" (Line 41) creates a configuration conflict. When browser mode is enabled in Vitest, the browser provides the environment, making the explicit environment: "jsdom" setting either redundant or potentially conflicting.

Resolution:

Remove the environment: "jsdom" line when using browser mode:

     browser: {
       enabled: true,
       provider: playwright({}),
       headless: true,
       instances: [
         {
           browser: "chromium",
         },
       ],
     },
     setupFiles: ["./.storybook/vitest.setup.ts"],
-    environment: "jsdom",
   },
 });

Additional note on Line 32:

The Playwright provider is configured with an empty object playwright({}). While this works with defaults, consider whether any explicit options (such as launch options or context configuration) would be beneficial for your test setup.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
browser: {
enabled: true,
provider: playwright({}),
headless: true,
instances: [
{
browser: "chromium",
},
],
},
setupFiles: ["./.storybook/vitest.setup.ts"],
environment: "jsdom",
},
browser: {
enabled: true,
provider: playwright({}),
headless: true,
instances: [
{
browser: "chromium",
},
],
},
setupFiles: ["./.storybook/vitest.setup.ts"],
},
});
🤖 Prompt for AI Agents
In test-storybooks/portable-stories-kitchen-sink/react/vite.config.ts around
lines 30 to 42, there is a conflicting Vitest config: browser.enabled is true
(line 31) while environment is explicitly set to "jsdom" (line 41); remove the
environment: "jsdom" line so the browser provider (Playwright) supplies the
environment, and optionally review the playwright({}) call on line 32 to add any
needed launch/context options if you require non-default behavior.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
.circleci/config.yml (2)

134-136: wait-on without timeout can hang jobs indefinitely

Multiple wait-on calls lack a timeout. Add a bounded timeout to avoid stuck pipelines.

Example change (replicate across all wait-on uses):

-  yarn wait-on tcp:127.0.0.1:6001
-  yarn wait-on tcp:127.0.0.1:6002
+  yarn wait-on -t 300000 tcp:127.0.0.1:6001
+  yarn wait-on -t 300000 tcp:127.0.0.1:6002

Also applies to: 156-158, 604-606, 635-637, 665-667


389-391: Guard artifact uploads to avoid step failures when directories are missing

store_artifacts can fail if the path doesn't exist (e.g., when tests abort early). Create the directory conditionally before upload.

Add a guard run step before each upload:

+  - run:
+      name: Ensure playwright results dir exists
+      command: mkdir -p code/playwright-results || true
   - store_artifacts:
       destination: playwright
       path: code/playwright-results/

Apply similarly for:

  • test-storybooks/portable-stories-kitchen-sink/react/test-results/
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/test-results/

Also applies to: 419-421, 441-445, 468-469

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0fbf790 and 5198b80.

⛔ Files ignored due to path filters (1)
  • test-storybooks/portable-stories-kitchen-sink/react/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • .circleci/README.md (1 hunks)
  • .circleci/config.yml (1 hunks)
  • .circleci/src/workflows/daily.yml (1 hunks)
  • .circleci/src/workflows/merged.yml (1 hunks)
  • .circleci/src/workflows/normal.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .circleci/README.md
  • .circleci/src/workflows/daily.yml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (2)
.circleci/config.yml (2)

95-95: Playwright image version aligns with guidance

Pinning to mcr.microsoft.com/playwright:v1.52.0-noble matches the recommended Playwright 1.52.0 for E2E.

Based on learnings


446-470: CI already exercises Vitest 4 sample via e2e-ui job
The existing e2e-ui job runs Playwright E2E against test-storybooks/portable-stories-kitchen-sink/react (Vitest 4).

Comment on lines 5 to 11
- run:
command: |
echo "Canceling workflow as previous step resulted in failure."
echo "To execute all checks locally, please run yarn ci-tests"
curl -X POST --header "Content-Type: application/json" "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel?circle-token=${WORKFLOW_CANCELER}"
name: Cancel current workflow
when: on_fail
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Avoid leaking CircleCI token in URL; use header and fail-fast curl

Passing the token via query string risks exposure in logs/proxies. Use the Circle-Token header and fail fast on errors.

Apply:

-          curl -X POST --header "Content-Type: application/json" "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel?circle-token=${WORKFLOW_CANCELER}"
+          curl -fsSL -X POST \
+            -H "Content-Type: application/json" \
+            -H "Circle-Token: ${WORKFLOW_CANCELER}" \
+            "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- run:
command: |
echo "Canceling workflow as previous step resulted in failure."
echo "To execute all checks locally, please run yarn ci-tests"
curl -X POST --header "Content-Type: application/json" "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel?circle-token=${WORKFLOW_CANCELER}"
name: Cancel current workflow
when: on_fail
- run:
command: |
echo "Canceling workflow as previous step resulted in failure."
echo "To execute all checks locally, please run yarn ci-tests"
curl -fsSL -X POST \
-H "Content-Type: application/json" \
-H "Circle-Token: ${WORKFLOW_CANCELER}" \
"https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel"
name: Cancel current workflow
when: on_fail
🤖 Prompt for AI Agents
In .circleci/config.yml around lines 5 to 11, the workflow cancel step is
leaking the CircleCI token in the query string and not failing fast; change the
curl invocation to send the token in the header (e.g., add -H "Circle-Token:
${WORKFLOW_CANCELER}") and remove the token from the URL, and add fail-fast curl
options such as --fail --silent --show-error (or at minimum --fail) so the step
returns a non-zero exit on error.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
code/addons/vitest/src/postinstall.ts (2)

86-93: Use coerced SemVer for version checks and clarify default assumptions.

satisfies(vitestVersionSpecifier, '>=x') will fail for ranges like ^3.2.1 or workspace:*. Use the already computed coercedVitestVersion instead.

Additionally, when vitestVersionSpecifier is null (vitest not yet installed), the defaults assume Vitest 3.2+ but not 4.0+. This could lead to incorrect package installation if the user is about to install Vitest 4.

Apply this diff to fix the version checks:

-  const isVitest3_2OrNewer = vitestVersionSpecifier
-    ? satisfies(vitestVersionSpecifier, '>=3.2.0')
+  const isVitest3_2OrNewer = coercedVitestVersion
+    ? satisfies(coercedVitestVersion, '>=3.2.0')
     : // TODO: Set to false once we have a stable release of Vitest 4
       true;
-  const isVitest4OrNewer = vitestVersionSpecifier
-    ? satisfies(vitestVersionSpecifier, '>=4.0.0')
+  const isVitest4OrNewer = coercedVitestVersion
+    ? satisfies(coercedVitestVersion, '>=4.0.0')
     : // TODO: Set to true once we have a stable release of Vitest 4
       false;

Based on learnings: Vitest 3.2.4 is the current stable release; Vitest 4 is not yet stable, which aligns with the TODO comments and current defaults.


515-531: Remove literal quotes from --config-dir argument.

The literal quotes around options.configDir will become part of the argument string, breaking paths with spaces. execa handles spaces safely without quotes.

Apply this diff:

       ...(options.configDir !== '.storybook' ? ['--config-dir', options.configDir] : []),
🧹 Nitpick comments (1)
code/addons/vitest/src/postinstall.ts (1)

455-466: Remove redundant conditional check.

Since getTemplateName() always returns a non-empty string (lines 397-405), the if (templateName) check at line 457 is always true and can be removed for clarity.

Apply this diff to simplify the logic:

 const templateName = getTemplateName();
 
-if (templateName) {
-  const configTemplate = await loadTemplate(templateName, {
-    CONFIG_DIR: options.configDir,
-    SETUP_FILE: relative(dirname(rootConfig), vitestSetupFile),
-  });
-
-  const source = babelParse(configTemplate);
-  target = babelParse(configFile);
-  updated = updateConfigFile(source, target);
-}
+const configTemplate = await loadTemplate(templateName, {
+  CONFIG_DIR: options.configDir,
+  SETUP_FILE: relative(dirname(rootConfig), vitestSetupFile),
+});
+
+const source = babelParse(configTemplate);
+target = babelParse(configFile);
+updated = updateConfigFile(source, target);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d3caab and 27c8a10.

📒 Files selected for processing (1)
  • code/addons/vitest/src/postinstall.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/addons/vitest/src/postinstall.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/addons/vitest/src/postinstall.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.284Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/vitest/src/postinstall.ts
🧬 Code graph analysis (1)
code/addons/vitest/src/postinstall.ts (2)
code/core/src/common/utils/get-storybook-info.ts (1)
  • getStorybookInfo (123-131)
code/addons/vitest/src/updateVitestFile.ts (1)
  • loadTemplate (9-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/addons/vitest/src/postinstall.ts (3)

95-104: LGTM! Version-aware dependency selection.

The dependency list correctly selects @vitest/browser-playwright for Vitest 4+ and @vitest/browser for earlier versions, and the filtering prevents reinstalling existing packages.


391-394: LGTM! Version-aware shim reference.

The shim reference correctly uses @vitest/browser-playwright for Vitest 4+ and @vitest/browser/providers/playwright for earlier versions, consistent with the dependency selection.


397-405: LGTM! Clean version-aware template selection.

The getTemplateName helper provides a clear, version-aware template selection mechanism that aligns with the version flags defined earlier.

@github-actions github-actions bot added the Stale label Oct 21, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44d087b and 8ae696f.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • code/addons/vitest/package.json (2 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/package.json (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test-storybooks/portable-stories-kitchen-sink/react/package.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest

Comment on lines 85 to 88
"@vitest/browser-playwright": "^4.0.1",
"@vitest/runner": "^4.0.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Vitest 4 support added with backward-compatible peer dependencies.

The changes appropriately upgrade to Vitest 4 while maintaining Vitest 3 compatibility in peer dependencies. The use of ^3.0.0 || ^4.0.0 ranges in peerDependencies allows users to continue using Vitest 3 while encouraging migration to Vitest 4.

However, there is an unresolved concern from a prior review:

Playwright version pinning — A previous review flagged that Playwright should be pinned to 1.52.0 in devDependencies for E2E consistency. Currently, no explicit Playwright dependency appears in this file. Since @vitest/browser-playwright is now a dependency, verify whether:

  1. Playwright is transitively pinned by @vitest/browser-playwright@^4.0.1, or
  2. An explicit "playwright": "1.52.0" entry is needed in devDependencies to guarantee E2E consistency across environments.

Also applies to: 104-104, 107-111, 117-119


🏁 Script executed:

#!/bin/bash
# Verify Playwright transitive dependency resolution and check if explicit pinning is needed
cd code/addons/vitest

# Check package-lock.json or yarn.lock for resolved Playwright version
if [ -f package-lock.json ]; then
  echo "=== Checking npm lock file ==="
  rg -A5 '"@vitest/browser-playwright"' package-lock.json | head -20
  rg '"playwright"' package-lock.json | head -10
elif [ -f yarn.lock ]; then
  echo "=== Checking yarn lock file ==="
  rg -A5 '@vitest/browser-playwright' yarn.lock | head -20
  rg 'playwright' yarn.lock | head -10
fi

# Check if Playwright is mentioned in any template package.json files
echo -e "\n=== Checking templates for Playwright references ==="
fd -g '*.json' templates/ -x grep -l playwright {} \;

Length of output: 53


I need to gather more information. The lock files may not have been present, and the grep results were inconclusive. Let me inspect the package.json directly and search for any Playwright pinning in the broader codebase.

I need to gather more information. The lock files may not have been present, and the grep results were inconclusive. Let me inspect the package.json directly and search for any Playwright pinning in the broader codebase.


🏁 Script executed:

#!/bin/bash
# Step 1: Check if the file exists and show its current state
echo "=== Listing files in code/addons/vitest/ ==="
ls -la code/addons/vitest/ | grep -E 'package.*json|lock'

echo -e "\n=== Current package.json (lines 80-125) ==="
sed -n '80,125p' code/addons/vitest/package.json

echo -e "\n=== Searching for Playwright in entire codebase ==="
rg -n -i 'playwright' --type json -C2 | grep -E '(package\.json|devDependencies|dependencies|peerDependencies)' -A2 -B2 | head -40

echo -e "\n=== Check root package.json for Playwright ==="
if [ -f package.json ]; then
  rg -n '"playwright"' package.json
fi

Length of output: 4352


🏁 Script executed:

#!/bin/bash
# Step 1: Check if the file exists and show its current state
echo "=== Listing files in code/addons/vitest/ ==="
ls -la code/addons/vitest/ | grep -E 'package.*json|lock'

echo -e "\n=== Current package.json (lines 80-125) ==="
sed -n '80,125p' code/addons/vitest/package.json

echo -e "\n=== Searching for Playwright in entire codebase ==="
rg -n -i 'playwright' --type json -C2 | head -50

echo -e "\n=== Check root package.json for Playwright ==="
if [ -f package.json ]; then
  rg -n '"playwright"' package.json
fi

Length of output: 6204


Add explicit Playwright version pinning to devDependencies.

The addon currently relies on transitive resolution of Playwright through @vitest/browser-playwright@^4.0.1, but does not explicitly pin the Playwright version. However, the entire codebase pins Playwright to 1.52.0 across all test-storybooks and scripts packages for E2E consistency:

  • test-storybooks/yarn-pnp/package.json
  • test-storybooks/portable-stories-kitchen-sink/vue3/package.json
  • test-storybooks/portable-stories-kitchen-sink/svelte/package.json
  • scripts/package.json

To maintain consistency and prevent transitive version drift, add "playwright": "1.52.0" to devDependencies in code/addons/vitest/package.json.

🤖 Prompt for AI Agents
In code/addons/vitest/package.json around lines 85-86, add an explicit
devDependency entry for "playwright": "1.52.0" inside the "devDependencies"
object alongside the existing @vitest entries to pin Playwright to 1.52.0; after
updating package.json run your package manager install (yarn/npm/pnpm) to update
the lockfile so the new pinned version is recorded.

@ndelangen ndelangen changed the base branch from next to yann/support-next-16 October 23, 2025 08:55
@ndelangen
Copy link
Member

@valentinpalkovic I've telescoped this on top of the other release un-blocker work @yannbf did, to get a green CI we can merge with.

@ndelangen ndelangen added ci:daily Run the CI jobs that normally run in the daily job. and removed ci:normal labels Oct 23, 2025
Copilot AI and others added 2 commits October 23, 2025 13:57
Only add `/// <reference types="vitest/config" />` 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 <[email protected]>
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 <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test-storybooks/portable-stories-kitchen-sink/react/package.json (1)

57-59: Align React type packages with React 18

You’re on react/react-dom ^18, but using @types/react and @types/react-dom ^19. Major mismatch can cause TS errors.

-    "@types/react": "^19.0.8",
-    "@types/react-dom": "^19.0.3",
+    "@types/react": "^18",
+    "@types/react-dom": "^18",

Also applies to: 73-75

🧹 Nitpick comments (3)
test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx (1)

2-2: Run Prettier on this file

Minor formatting: missing semicolon.

-import { sb } from 'storybook/test'
+import { sb } from 'storybook/test';

As per coding guidelines (Prettier/ESLint).

code/addons/vitest/src/vitest-plugin/test-utils.ts (2)

17-24: Make convertToFilePath robust and cross‑platform

Decode all URL encodings and handle Windows/posix uniformly via URL parsing.

-export const convertToFilePath = (url: string): string => {
-  // Remove the file:// protocol
-  const path = url.replace(/^file:\/\//, '');
-  // Handle Windows paths
-  const normalizedPath = path.replace(/^\/+([a-zA-Z]:)/, '$1');
-  // Convert %20 to spaces
-  return normalizedPath.replace(/%20/g, ' ');
-};
+export const convertToFilePath = (url: string): string => {
+  try {
+    const u = new URL(url);
+    let p = decodeURIComponent(u.pathname);
+    // Windows drive letter (e.g., /C:/path -> C:/path)
+    p = p.replace(/^\/+([a-zA-Z]:)/, '$1');
+    return p;
+  } catch {
+    // Fallback: treat as already a path
+    return url;
+  }
+};

44-47: Safer access to getInitialGlobals

Avoid destructuring from possibly missing server.commands. Use optional chaining.

-    const { server } = await getVitestBrowserContext();
-
-    const { getInitialGlobals } = server.commands;
+    const ctx = await getVitestBrowserContext();
+    const getInitialGlobals = ctx?.server?.commands?.getInitialGlobals;

Also applies to: 48-55

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 130fdda and d236c85.

⛔ Files ignored due to path filters (2)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • test-storybooks/portable-stories-kitchen-sink/react-vitest-3/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (10)
  • .circleci/config.yml (4 hunks)
  • .circleci/src/workflows/daily.yml (1 hunks)
  • .circleci/src/workflows/merged.yml (1 hunks)
  • .circleci/src/workflows/normal.yml (1 hunks)
  • code/addons/vitest/src/vitest-plugin/test-utils.ts (2 hunks)
  • code/addons/vitest/src/vitest-plugin/viewports.ts (2 hunks)
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts (1 hunks)
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • .circleci/src/workflows/merged.yml
  • .circleci/config.yml
  • code/addons/vitest/src/vitest-plugin/viewports.ts
  • .circleci/src/workflows/daily.yml
  • .circleci/src/workflows/normal.yml
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
  • test-storybooks/portable-stories-kitchen-sink/react/package.json
**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Export functions from modules when they need to be unit-tested

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
code/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In application code, use Storybook loggers instead of console.* (client code: storybook/internal/client-logger; server code: storybook/internal/node-logger)

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
{code/**,scripts/**}/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
test-storybooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain test Storybook configurations under test-storybooks/ for E2E and visual testing scenarios

Files:

  • test-storybooks/portable-stories-kitchen-sink/react/package.json
🧠 Learnings (2)
📚 Learning: 2025-09-24T09:39:39.233Z
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.233Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx
📚 Learning: 2025-10-13T13:33:14.659Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-13T13:33:14.659Z
Learning: Applies to **/*.@(test|spec).{ts,tsx,js,jsx} : Mock external dependencies in tests using `vi.mock()` (e.g., filesystem, loggers)

Applied to files:

  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
🧬 Code graph analysis (2)
test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx (1)
code/core/src/test/index.ts (1)
  • sb (54-60)
code/addons/vitest/src/vitest-plugin/test-utils.ts (1)
code/addons/vitest/src/vitest-plugin/vitest-context.ts (1)
  • getVitestBrowserContext (14-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts (1)

43-44: LGTM! Vitest 4 node mocker support correctly implemented.

The changes consistently extend the existing pattern:

  • '@vitest/mocker/node' is added to optimizeDeps.include alongside the existing browser and base variants
  • The corresponding alias mapping follows the same resolution pattern used for other mocker modules
  • Excluding fsevents (a macOS-specific native module) from optimization is a standard best practice

All three additions work together to ensure proper resolution and optimization of Vitest 4's node-specific mocker module, particularly for package managers like pnpm as noted in the existing comment.

Also applies to: 51-51

test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx (1)

5-5: The review comment requires verification against official Storybook documentation

Based on official Storybook documentation, when registering a mock for a local module, the path must include the file extension (e.g., .ts or .js). The code as written—sb.mock('./get-decorator-string.ts', { spy: true })—actually follows this requirement correctly by including the .ts extension.

The review comment suggests removing the extension, but this contradicts Storybook's documented requirement that local module paths must include the file extension. Without access to verify the actual import statements in the file or evidence that imports omit the extension while the mock includes it, the suggestion to remove the extension appears to conflict with Storybook's explicit guidance.

Likely an incorrect or invalid review comment.

test-storybooks/portable-stories-kitchen-sink/react/package.json (1)

77-81: I need to gather more specific information to complete the verification. Let me search for the exact peer dependencies and Storybook 10 compatibility:

Let me search for the actual package.json file to verify the complete context and see lines 89-93 mentioned in the review:

Compatibility verified—no issues found.

Vite 7 is supported by Vitest 4 and is compatible with @vitejs/plugin-react v5. @vitest/browser-playwright v4 is a separate provider package paired with Vitest 4. Storybook maintains compatibility across Vitest versions and supports Vitest 2.1.x, with no constraints preventing Storybook 10 from working with Vitest 4. The version ranges in lines 77–81 and 89–93 satisfy all peer dependencies and are mutually compatible.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/addons/vitest/src/postinstall.ts (1)

295-301: Now let me check the actual context in the postinstall.ts file to understand what dependencies are being processed:

Correct the version pinning logic to only match the exact 'vitest' package.

The current includes('vitest') match is overly broad and will incorrectly pin @vitest/browser and other @vitest/* packages to the vitest version, which can resolve to non-existent versions since these packages won't play nicely if they differ in versions, but require independent version management.

Use exact string matching instead:

-  const versionedDependencies = uniqueDependencies.map((p) => {
-    if (p.includes('vitest')) {
-      return vitestVersionSpecifier ? `${p}@${vitestVersionSpecifier}` : p;
-    }
-    return p;
-  });
+  const versionedDependencies = uniqueDependencies.map((p) =>
+    p === 'vitest' && vitestVersionSpecifier ? `${p}@${vitestVersionSpecifier}` : p
+  );
♻️ Duplicate comments (2)
code/addons/vitest/src/postinstall.ts (2)

86-91: Use coerced SemVer for range checks (specifier can mis-evaluate).

Compare against coercedVitestVersion, not the raw specifier (handles ^3.2.1, workspace:*, etc.).

Apply:

-  const isVitest3_2To4 = vitestVersionSpecifier
-    ? satisfies(vitestVersionSpecifier, '>=3.2.0 <4.0.0')
+  const isVitest3_2To4 = coercedVitestVersion
+    ? satisfies(coercedVitestVersion, '>=3.2.0 <4.0.0')
     : false;
-  const isVitest4OrNewer = vitestVersionSpecifier
-    ? satisfies(vitestVersionSpecifier, '>=4.0.0')
+  const isVitest4OrNewer = coercedVitestVersion
+    ? satisfies(coercedVitestVersion, '>=4.0.0')
     : true;

515-531: Do not quote argv values passed to execa (quotes become literal).

Let execa handle spaces; pass raw path.

-          ...(options.configDir !== '.storybook' ? ['--config-dir', `"${options.configDir}"`] : []),
+          ...(options.configDir !== '.storybook' ? ['--config-dir', options.configDir] : []),
🧹 Nitpick comments (2)
code/addons/vitest/src/updateVitestFile.ts (1)

252-269: Coverage extraction looks right; add a duplicate guard.

Logic is solid. To be defensive, avoid inserting a second coverage if a template already provides one.

Apply this small guard:

-                if (coverageProp && templateTestProp.value.type === 'ObjectExpression') {
-                  templateTestProp.value.properties.unshift(coverageProp);
-                }
+                if (
+                  coverageProp &&
+                  templateTestProp.value.type === 'ObjectExpression' &&
+                  !templateTestProp.value.properties.some(
+                    (p) =>
+                      p.type === 'ObjectProperty' &&
+                      p.key.type === 'Identifier' &&
+                      p.key.name === 'coverage'
+                  )
+                ) {
+                  templateTestProp.value.properties.unshift(coverageProp);
+                }

Also applies to: 300-304

code/addons/vitest/src/updateVitestFile.test.ts (1)

10-16: Adopt spy-based mocks and vi.mocked() per repo test guidelines.

Use spy: true and move behavior into beforeEach with vi.mocked(...) for type-safety.

As per coding guidelines

Example minimal change for the logger mock:

-vi.mock('storybook/internal/node-logger', () => ({
-  logger: {
-    info: vi.fn(),
-    warn: vi.fn(),
-    error: vi.fn(),
-  },
-}));
+vi.mock('storybook/internal/node-logger', { spy: true });
+// later at top-level or in beforeEach():
+// const { logger } = await import('storybook/internal/node-logger');
+// vi.mocked(logger.info).mockReset();
+// vi.mocked(logger.warn).mockReset();
+// vi.mocked(logger.error).mockReset();

For resolvePackageDir, you can similarly:

-vi.mock('../../../core/src/shared/utils/module', () => ({
-  resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),
-}));
+vi.mock('../../../core/src/shared/utils/module', { spy: true });
+// in beforeEach:
+// const { resolvePackageDir } = await import('../../../core/src/shared/utils/module');
+// vi.mocked(resolvePackageDir).mockReturnValue(join(__dirname, '..'));

Also applies to: 18-20

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d236c85 and ad8d67f.

📒 Files selected for processing (3)
  • code/addons/vitest/src/postinstall.ts (8 hunks)
  • code/addons/vitest/src/updateVitestFile.test.ts (11 hunks)
  • code/addons/vitest/src/updateVitestFile.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/src/postinstall.ts
  • code/addons/vitest/src/updateVitestFile.test.ts
  • code/addons/vitest/src/updateVitestFile.ts
**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Export functions from modules when they need to be unit-tested

Files:

  • code/addons/vitest/src/postinstall.ts
  • code/addons/vitest/src/updateVitestFile.test.ts
  • code/addons/vitest/src/updateVitestFile.ts
code/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In application code, use Storybook loggers instead of console.* (client code: storybook/internal/client-logger; server code: storybook/internal/node-logger)

Files:

  • code/addons/vitest/src/postinstall.ts
  • code/addons/vitest/src/updateVitestFile.test.ts
  • code/addons/vitest/src/updateVitestFile.ts
{code/**,scripts/**}/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/vitest/src/postinstall.ts
  • code/addons/vitest/src/updateVitestFile.test.ts
  • code/addons/vitest/src/updateVitestFile.ts
code/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

code/**/*.{test,spec}.{ts,tsx}: Place all test files under the code/ directory
Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access mocked functions
Implement mock behaviors in beforeEach blocks
Mock all required dependencies that the test subject uses
Mock implementations should be placed in beforeEach blocks
Each mock implementation should return a Promise for async functions
Mock implementations should match the expected return type of the original function
Use vi.mocked() to access and implement mock behaviors
Mock all required properties and methods that the test subject uses
Avoid direct function mocking without vi.mocked()
Avoid mock implementations outside of beforeEach blocks
Avoid mocking without the spy: true option
Avoid inline mock implementations within test cases
Avoid mocking only a subset of required dependencies
Mock at the highest level of abstraction needed
Keep mock implementations simple and focused
Use type-safe mocking with vi.mocked()
Document complex mock behaviors
Group related mocks together

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
**/*.@(test|spec).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.@(test|spec).{ts,tsx,js,jsx}: Unit tests should import and execute the functions under test rather than only asserting on syntax patterns
Mock external dependencies in tests using vi.mock() (e.g., filesystem, loggers)

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
🧠 Learnings (2)
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/vitest/src/postinstall.ts
  • code/addons/vitest/src/updateVitestFile.test.ts
📚 Learning: 2025-10-13T13:33:14.659Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-13T13:33:14.659Z
Learning: Applies to test-storybooks/** : Maintain test Storybook configurations under `test-storybooks/` for E2E and visual testing scenarios

Applied to files:

  • code/addons/vitest/src/updateVitestFile.test.ts
🧬 Code graph analysis (2)
code/addons/vitest/src/postinstall.ts (2)
code/core/src/common/utils/get-storybook-info.ts (1)
  • getStorybookInfo (123-131)
code/addons/vitest/src/updateVitestFile.ts (1)
  • loadTemplate (9-16)
code/addons/vitest/src/updateVitestFile.test.ts (1)
code/addons/vitest/src/updateVitestFile.ts (2)
  • loadTemplate (9-16)
  • updateConfigFile (79-325)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/addons/vitest/src/postinstall.ts (3)

390-392: TS shim reference looks good; minor: broaden provider fallback?

Reference selection by version is correct. If you later support non-Playwright providers on Vitest 4+, consider deriving types from chosen provider.


395-403: Template selection logic LGTM.

Clear 4.x/3.2+ split with default fallback.


471-479: Nice: triple-slash reference only for vite.config files.

Good guard to avoid duplicate references in vitest.config.*.

Comment on lines 272 to 277
try {
const storybookVersion = await packageManager.getInstalledVersion('storybook');
dependencies.push(`@storybook/nextjs-vite@^${storybookVersion}`);
uniqueDependencies.push(`@storybook/nextjs-vite@^${storybookVersion}`);
} catch (e) {
console.error('Failed to install @storybook/nextjs-vite. Please install it manually');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Use Storybook logger instead of console.error (repo guideline).

Replace console.error with logger.error for consistency.

As per coding guidelines

-      console.error('Failed to install @storybook/nextjs-vite. Please install it manually');
+      logger.error('Failed to install @storybook/nextjs-vite. Please install it manually');
@@
-      console.error('Failed to install Playwright. Please install it manually');
+      logger.error('Failed to install Playwright. Please install it manually');

Also applies to: 324-330


🏁 Script executed:

#!/bin/bash
rg -n "console\\.(error|warn|log)\\(" code/addons/vitest/src/postinstall.ts -n

Length of output: 181


Now I'll check the actual file to see if the logger is already imported:


🏁 Script executed:

#!/bin/bash
# Check imports at the top of the vitest postinstall file
head -40 code/addons/vitest/src/postinstall.ts
echo "---"
# Check the specific lines with console.error
sed -n '270,280p' code/addons/vitest/src/postinstall.ts
echo "---"
sed -n '320,335p' code/addons/vitest/src/postinstall.ts

Length of output: 2570


Replace console.error with logger.error to comply with Storybook coding guidelines.

The logger is already imported in the file at line 20 and used consistently elsewhere. Replace both occurrences:

-      console.error('Failed to install @storybook/nextjs-vite. Please install it manually');
+      logger.error('Failed to install @storybook/nextjs-vite. Please install it manually');
-      console.error('Failed to install Playwright. Please install it manually');
+      logger.error('Failed to install Playwright. Please install it manually');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
const storybookVersion = await packageManager.getInstalledVersion('storybook');
dependencies.push(`@storybook/nextjs-vite@^${storybookVersion}`);
uniqueDependencies.push(`@storybook/nextjs-vite@^${storybookVersion}`);
} catch (e) {
console.error('Failed to install @storybook/nextjs-vite. Please install it manually');
}
try {
const storybookVersion = await packageManager.getInstalledVersion('storybook');
uniqueDependencies.push(`@storybook/nextjs-vite@^${storybookVersion}`);
} catch (e) {
logger.error('Failed to install @storybook/nextjs-vite. Please install it manually');
}
🤖 Prompt for AI Agents
In code/addons/vitest/src/postinstall.ts around lines 272 to 277, replace the
console.error call with logger.error (the logger is already imported at line
20); change the catch block to call logger.error('Failed to install
@storybook/nextjs-vite. Please install it manually', e) so the error is logged
consistently and preserve the original error details, and remove any unused
console references elsewhere if present.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
code/addons/vitest/src/updateVitestFile.test.ts (2)

1-1: Add required imports for the ESM-safe mock.

Needed by the refactor above.

-import { join } from 'node:path';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';

18-20: Add { spy: true } to both vi.mock() calls per Vitest testing guidelines.

The test file has two vi.mock() calls (lines 10–16 and 18–20) that lack the { spy: true } option. Per your guidelines, all module mocks in Vitest tests must include this option to enable proper spy behavior while preserving original implementations.

Apply to both mocks:

 vi.mock('storybook/internal/node-logger', () => ({
   logger: {
     info: vi.fn(),
     warn: vi.fn(),
     error: vi.fn(),
   },
-}));
+}), { spy: true });

 vi.mock('../../../core/src/shared/utils/module', () => ({
   resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),
-}));
+}), { spy: true });

Optionally, add afterEach(() => vi.restoreAllMocks()) after the mock declarations to reset mock state between tests.

🧹 Nitpick comments (4)
code/addons/vitest/src/updateVitestFile.test.ts (4)

10-16: Use spy mocks and ensure cleanup.

Per guidelines, enable spies and restore between tests.

Apply:

-vi.mock('storybook/internal/node-logger', () => ({
+vi.mock('storybook/internal/node-logger', () => ({
   logger: {
     info: vi.fn(),
     warn: vi.fn(),
     error: vi.fn(),
   },
-}));
+}), { spy: true });

Also add an afterEach to restore mocks (see next comment). As per coding guidelines.


3-3: Restore mocks after each test.

Prevents cross-test leakage.

-import { describe, expect, it, vi } from 'vitest';
+import { describe, expect, it, vi, afterEach } from 'vitest';
+afterEach(() => {
+  vi.restoreAllMocks();
+});

Also applies to: 22-22


56-101: Reduce snapshot brittleness; assert stable invariants instead.

Inline snapshots of full diffs are fragile across formatter/Babel/Vitest version shifts. Prefer focused assertions on key invariants (e.g., presence of storybookTest import, dirname fallback, workspace/projects entries, and the browser block) or AST-level checks.

Example direction (illustrative):

  • expect(after).toContain("@storybook/addon-vitest/vitest-plugin")
  • expect(after).toMatch(/workspace:\s*[/s)
  • expect(after).toMatch(/browser:\s*{[\s\S]?provider:\s'playwright'/)

Keeps tests resilient while still verifying behavior.

Also applies to: 135-180, 247-291, 327-371, 406-450, 482-525, 564-612, 646-688, 725-772, 800-830, 858-889


141-149: Unused import in “object notation” snapshot.

The expected diff adds import { defineConfig } from 'vitest/config' but the resulting file continues to export a plain object. That import would be unused and likely fail linting in user projects.

  • If intentional, document why the import is needed.
  • Otherwise, adjust updateConfigFile to avoid injecting unused imports and update this snapshot accordingly.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad8d67f and 423d58b.

📒 Files selected for processing (1)
  • code/addons/vitest/src/updateVitestFile.test.ts (11 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
code/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

code/**/*.{test,spec}.{ts,tsx}: Place all test files under the code/ directory
Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access mocked functions
Implement mock behaviors in beforeEach blocks
Mock all required dependencies that the test subject uses
Mock implementations should be placed in beforeEach blocks
Each mock implementation should return a Promise for async functions
Mock implementations should match the expected return type of the original function
Use vi.mocked() to access and implement mock behaviors
Mock all required properties and methods that the test subject uses
Avoid direct function mocking without vi.mocked()
Avoid mock implementations outside of beforeEach blocks
Avoid mocking without the spy: true option
Avoid inline mock implementations within test cases
Avoid mocking only a subset of required dependencies
Mock at the highest level of abstraction needed
Keep mock implementations simple and focused
Use type-safe mocking with vi.mocked()
Document complex mock behaviors
Group related mocks together

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
**/*.@(test|spec).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.@(test|spec).{ts,tsx,js,jsx}: Unit tests should import and execute the functions under test rather than only asserting on syntax patterns
Mock external dependencies in tests using vi.mock() (e.g., filesystem, loggers)

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Export functions from modules when they need to be unit-tested

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
code/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In application code, use Storybook loggers instead of console.* (client code: storybook/internal/client-logger; server code: storybook/internal/node-logger)

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
{code/**,scripts/**}/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/vitest/src/updateVitestFile.test.ts
🧠 Learnings (2)
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/vitest/src/updateVitestFile.test.ts
📚 Learning: 2025-10-13T13:33:14.659Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-13T13:33:14.659Z
Learning: Applies to test-storybooks/** : Maintain test Storybook configurations under `test-storybooks/` for E2E and visual testing scenarios

Applied to files:

  • code/addons/vitest/src/updateVitestFile.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest

- 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.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
code/addons/vitest/package.json (1)

85-110: Backward-compatible Vitest 4 support is well-structured.

The upgrade to Vitest 4 in devDependencies while maintaining backward-compatible peer dependency ranges (^3.0.0 || ^4.0.0) allows users to gradually migrate from Vitest 3 to 4. The switch from @vitest/browser to @vitest/browser-playwright in devDependencies aligns with Vitest 4's architecture.

However, a previous review comment flagged that Playwright should be explicitly pinned to 1.52.0 in devDependencies for E2E consistency across the codebase. This remains unaddressed.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 423d58b and 9f996c3.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • code/addons/vitest/package.json (2 hunks)
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts (1 hunks)
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/core/src/core-server/presets/vitePlugins/vite-inject-mocker/plugin.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • test-storybooks/portable-stories-kitchen-sink/react/package.json
  • code/addons/vitest/package.json
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
test-storybooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain test Storybook configurations under test-storybooks/ for E2E and visual testing scenarios

Files:

  • test-storybooks/portable-stories-kitchen-sink/react/package.json
**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Export functions from modules when they need to be unit-tested

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
code/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In application code, use Storybook loggers instead of console.* (client code: storybook/internal/client-logger; server code: storybook/internal/node-logger)

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
{code/**,scripts/**}/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Use Vitest as the test runner for this repository
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (2)
test-storybooks/portable-stories-kitchen-sink/react/package.json (1)

63-93: LGTM! Version upgrades align with Vitest 4 and Storybook 10 migration.

All dependency updates are consistent and support the PR's goal of adding Vitest 4 compatibility while upgrading the Storybook ecosystem to v10.

code/addons/vitest/src/vitest-plugin/vitest-context.ts (1)

3-11: LGTM! Type definitions appropriately extend Vitest context.

The type structure correctly extends VitestBrowserContext with the custom getInitialGlobals command, providing proper typing for the server context augmentation.

@@ -0,0 +1,24 @@
import semver from 'semver';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Replace version sniffing with feature detection to improve robustness.

The current approach uses JSON import attributes and semver to detect Vitest version, but this has several drawbacks:

  1. Import attributes brittleness: JSON import attributes (with: { type: 'json' }) are not universally supported across all Node versions and bundlers, and the module shape may vary (direct properties vs default.version).
  2. Runtime overhead: Adding semver as a runtime dependency just for version detection is heavy.
  3. Maintenance burden: Version checks require updates when Vitest changes its versioning scheme.

A previous review comment suggested using feature detection instead, which is more robust and eliminates the semver dependency.

Apply the feature detection approach suggested in the prior review:

-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<Record<string, any>>;
     };
   };
 };
 
-/** Gets the Vitest browser context based on which version of Vitest is installed. */
+/** Gets the Vitest browser context by feature detection (v4 first, then v3). */
 export const getVitestBrowserContext = async (): Promise<VitestServerContext> => {
-  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<VitestServerContext>;
+  try {
+    return (await import('vitest/browser')) as unknown as VitestServerContext;
+  } catch {
+    return (await import('@vitest/browser/context')) as unknown as VitestServerContext;
   }
-
-  return import('@vitest/browser/context') as Promise<VitestServerContext>;
 };

Optionally, add caching to avoid repeated dynamic imports:

let _ctxPromise: Promise<VitestServerContext> | undefined;

export const getVitestBrowserContext = async (): Promise<VitestServerContext> => {
  if (_ctxPromise) return _ctxPromise;
  _ctxPromise = (async () => {
    try {
      return (await import('vitest/browser')) as unknown as VitestServerContext;
    } catch {
      return (await import('@vitest/browser/context')) as unknown as VitestServerContext;
    }
  })();
  return _ctxPromise;
};

Also applies to: 15-20

🤖 Prompt for AI Agents
In code/addons/vitest/src/vitest-plugin/vitest-context.ts around lines 1 and
15-20, replace the current Vitest version-sniffing logic (including the semver
dependency and JSON import-attributes) with feature-detection via attempting to
import the newer module path first and falling back to the older one; implement
an async cached loader (a top-level Promise variable) so repeated calls reuse
the same dynamic import result; remove the semver import and any JSON-with-type
import logic and update exports to use the resolved module shape directly as the
VitestServerContext.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/addons/vitest/src/vitest-plugin/test-utils.ts (1)

17-24: Incomplete URL decoding: use decodeURIComponent for all encoded characters.

The function only decodes %20 (spaces) but URLs can contain many other encoded characters (%2F, %3A, %28, %29, etc.). This will cause issues with file paths containing these characters.

Apply this diff to properly decode all URL-encoded characters:

 export const convertToFilePath = (url: string): string => {
   // Remove the file:// protocol
   const path = url.replace(/^file:\/\//, '');
   // Handle Windows paths
   const normalizedPath = path.replace(/^\/+([a-zA-Z]:)/, '$1');
-  // Convert %20 to spaces
-  return normalizedPath.replace(/%20/g, ' ');
+  // Decode all URL-encoded characters
+  return decodeURIComponent(normalizedPath);
 };
♻️ Duplicate comments (1)
code/addons/vitest/package.json (1)

87-88: Add explicit Playwright pinning for E2E consistency.

As noted in previous reviews, explicit Playwright version pinning to 1.52.0 is missing. While @vitest/browser-playwright@^4.0.1 brings Playwright transitively, the version could drift across installs. Other test storybooks in the repo (test-storybooks/yarn-pnp, portable-stories-kitchen-sink/vue3, etc.) explicitly pin to 1.52.0 for E2E consistency.

Apply this diff to pin Playwright:

   "@types/semver": "^7",
   "@vitest/browser-playwright": "^4.0.1",
   "@vitest/runner": "^4.0.1",
+  "playwright": "1.52.0",
   "boxen": "^8.0.1",

Based on learnings

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f996c3 and 2e5c563.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (10)
  • code/addons/vitest/build-config.ts (1 hunks)
  • code/addons/vitest/package.json (3 hunks)
  • code/addons/vitest/src/vitest-plugin/index.ts (7 hunks)
  • code/addons/vitest/src/vitest-plugin/test-utils.ts (2 hunks)
  • code/addons/vitest/src/vitest-plugin/types.ts (1 hunks)
  • code/addons/vitest/src/vitest-plugin/viewports.ts (2 hunks)
  • code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts (1 hunks)
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts (1 hunks)
  • test-storybooks/portable-stories-kitchen-sink/react/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/addons/vitest/src/vitest-plugin/index.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts
  • code/addons/vitest/src/vitest-plugin/types.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/build-config.ts
  • code/addons/vitest/src/vitest-plugin/viewports.ts
  • code/addons/vitest/package.json
  • test-storybooks/portable-stories-kitchen-sink/react/package.json
**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Export functions from modules when they need to be unit-tested

Files:

  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts
  • code/addons/vitest/src/vitest-plugin/types.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/build-config.ts
  • code/addons/vitest/src/vitest-plugin/viewports.ts
code/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In application code, use Storybook loggers instead of console.* (client code: storybook/internal/client-logger; server code: storybook/internal/node-logger)

Files:

  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/addons/vitest/src/vitest-plugin/types.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/build-config.ts
  • code/addons/vitest/src/vitest-plugin/viewports.ts
{code/**,scripts/**}/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/vitest/src/vitest-plugin/test-utils.ts
  • code/addons/vitest/src/vitest-plugin/types.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/build-config.ts
  • code/addons/vitest/src/vitest-plugin/viewports.ts
test-storybooks/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain test Storybook configurations under test-storybooks/ for E2E and visual testing scenarios

Files:

  • test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts
  • test-storybooks/portable-stories-kitchen-sink/react/package.json
🧠 Learnings (1)
📚 Learning: 2025-10-13T13:33:14.659Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-13T13:33:14.659Z
Learning: Applies to **/*.{ts,tsx,js,jsx,mjs} : Export functions from modules when they need to be unit-tested

Applied to files:

  • code/addons/vitest/build-config.ts
🧬 Code graph analysis (2)
code/addons/vitest/src/vitest-plugin/test-utils.ts (1)
code/addons/vitest/src/vitest-plugin/types.ts (1)
  • VitestBrowserContext (13-18)
code/addons/vitest/src/vitest-plugin/viewports.ts (1)
code/addons/vitest/src/vitest-plugin/types.ts (1)
  • VitestBrowserContext (13-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (14)
test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts (1)

20-20: No issues found—the import change is correct and follows Cypress best practices.

The change from cypress/react18 to cypress/react is the official Cypress migration path, as the separate react18 harness has been merged into cypress/react. For React 18+, the correct import is cypress/react. Verification confirms no other cypress/react18 imports remain in the codebase, so the migration is complete and consistent.

code/addons/vitest/src/vitest-plugin/test-utils.ts (2)

1-9: LGTM: Imports are clean and necessary.

The removal of toTestId is appropriate since it's not used in the file, and the addition of VitestBrowserContext supports the new dynamic context retrieval pattern.


51-57: LGTM: Defensive handling of getInitialGlobals.

The use of optional chaining (getInitialGlobals?.()) and nullish coalescing (?? {}) properly handles cases where the command might not be available, ensuring the story composition doesn't fail due to missing globals.

code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts (1)

1-1: LGTM: Clean re-export for Vitest 4+ browser context.

The barrel export correctly proxies the modern Vitest browser API surface for version-aware resolution.

code/addons/vitest/src/vitest-plugin/types.ts (2)

3-18: Well-structured type extensions for Vitest browser context.

The type declarations cleanly model the extended browser context with optional a11y configuration and server commands. The structure properly extends Vitest's base types.


1-1: Based on the web search results, I found critical information. Vitest 4's migration guide states that imports should be updated from @vitest/browser/context to vitest/browser. This is a breaking API change in Vitest 4.

Now I have key information. Let me check one more aspect: how types.ts is used and whether it's exposed as part of the public API or only internally.

Based on my comprehensive verification, I can now provide the final assessment:

Update import path for Vitest 4 forward compatibility.

While @vitest/browser/context will keep working until the next major version in Vitest 4, it is deprecated. The recommended path for Vitest 4+ is vitest/browser. Since types.ts is not version-gated unlike vitest-context.ts and vitest-context-legacy.ts, update the import to use vitest/browser to ensure forward compatibility:

import type { BrowserCommands, BrowserPage } from 'vitest/browser';

This aligns with Vitest's migration guidance and maintains support for both Vitest 3 and 4 in the supported version range (^3.0.0 || ^4.0.0).

code/addons/vitest/src/vitest-plugin/viewports.ts (2)

5-7: Good: Streamlined imports.

The change correctly narrows the import to only ViewportMap and adds the local VitestBrowserContext type, improving clarity and reducing unnecessary imports.


71-74: Correct: Version-aware context import with proper error handling.

The switch to the internal vitest-context path enables runtime resolution based on Vitest version. The error handling and type cast are appropriate for this dynamic import pattern.

code/addons/vitest/build-config.ts (1)

25-34: Correct: Build entries for internal context modules.

The new browser build entries properly expose the version-aware context modules as internal exports. The dts: false setting is appropriate for these runtime-resolved shims.

test-storybooks/portable-stories-kitchen-sink/react/package.json (1)

63-66: LGTM: Comprehensive dependency upgrades for Vitest 4 support.

The coordinated upgrade of Storybook (to v10), Vitest (to v4), and related tooling is consistent and complete. The addition of @testing-library/dom and @vitest/browser-playwright properly supports Vitest 4's browser testing capabilities.

Also applies to: 69-69, 77-82, 90-90, 92-93

code/addons/vitest/package.json (4)

49-50: Correct: Internal context exports added.

The new export paths properly expose the version-aware context modules and align with the build configuration entries.


87-88: Good: DevDependencies upgraded for Vitest 4.

The addition of @vitest/browser-playwright and upgrade of @vitest/runner to v4 properly support Vitest 4's browser testing infrastructure.


109-112: Excellent: Backward-compatible peer dependency ranges.

The ^3.0.0 || ^4.0.0 ranges correctly enable users to continue using Vitest 3 while supporting migration to Vitest 4, aligning with the PR's compatibility goals.


114-117: Based on my investigation, the original review comment is accurate. The addon-vitest is designed to provide a better testing experience and projects using React, Vue, or Svelte built with Vite should consider migrating to it, but the change to make @vitest/browser and vitest required peer dependencies (by removing them from peerDependenciesMeta) is indeed a breaking change that requires all users to have these packages installed.

However, I found no documentation in the migration guide specifically addressing this breaking change for the vitest addon. While the change itself is valid (these are core dependencies for the addon to function), the lack of explicit documentation about this requirement is a concern.

Ensure this breaking change is documented in migration materials.

The removal of @vitest/browser and vitest from peerDependenciesMeta makes them required peer dependencies (previously optional). While this may be necessary for the addon's functionality, update the Storybook 9 migration guide to explicitly document:

  • That @vitest/browser and vitest ^3.0.0 || ^4.0.0 are now required
  • Migration steps for users who had these as optional
  • Compatibility implications for existing projects

Comment on lines +44 to +49
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify runtime alias resolution and consider adding error handling.

The dynamic import relies on the vitest plugin to resolve the '@storybook/addon-vitest/internal/vitest-context' alias at runtime. If the alias is not properly configured or the imported module doesn't match the expected VitestBrowserContext shape, the type assertion will fail silently, leading to unclear runtime errors when accessing server.commands.

Run the following script to verify that the vitest plugin properly sets up this alias:

Consider adding runtime error handling to provide clearer error messages if the import fails:

let server: VitestBrowserContext['server'];
try {
  const context = (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;
  server = context.server;
} catch (error) {
  throw new Error(
    'Failed to load vitest context. Ensure the vitest plugin is properly configured.',
    { cause: error }
  );
}

const { getInitialGlobals } = server.commands;

🏁 Script executed:

#!/bin/bash
# Description: Verify the vitest-context alias is configured in the vitest plugin

# Find the vitest plugin configuration
echo "=== Searching for vitest-context alias configuration ==="
rg -n "vitest-context" --type=ts -C 3

echo ""
echo "=== Searching for alias resolution in vitest plugin ==="
rg -n "resolve.*alias" code/addons/vitest/src/vitest-plugin/ --type=ts -C 5

Length of output: 3824


🏁 Script executed:

#!/bin/bash
# Verify vitest-context exports and error handling patterns

echo "=== Checking vitest-context.ts exports ==="
cat code/addons/vitest/src/vitest-plugin/vitest-context.ts

echo ""
echo "=== Checking vitest-context-legacy.ts exports ==="
cat code/addons/vitest/src/vitest-plugin/vitest-context-legacy.ts

echo ""
echo "=== Checking full context of test-utils.ts function ==="
cat code/addons/vitest/src/vitest-plugin/test-utils.ts

Length of output: 3703


🏁 Script executed:

#!/bin/bash
# Verify the actual module exports and usage patterns

echo "=== Searching for other imports from vitest-context alias ==="
rg -n "@storybook/addon-vitest/internal/vitest-context" --type=ts -B2 -A2

echo ""
echo "=== Checking how @vitest/browser is imported elsewhere ==="
rg -n "from ['\"](vitest|@vitest)" code/addons/vitest/src/vitest-plugin/ --type=ts | head -20

echo ""
echo "=== Check if there's module augmentation in types.ts ==="
cat code/addons/vitest/src/vitest-plugin/types.ts | head -50

Length of output: 5022


Add error handling and verify vitest-context.ts exports destructurable members for Vitest 4+ compatibility.

The dynamic import relies on @storybook/addon-vitest/internal/vitest-context exporting a server property, but vitest-context.ts (Vitest 4+ path) only exports a named function getVitestBrowserContext and does not re-export destructurable members like vitest-context-legacy.ts does. This will cause a runtime error when test-utils.ts attempts to destructure { server } on Vitest 4+.

The pattern shown in viewports.ts with error handling demonstrates the appropriate defensive approach:

const { server } = (await import(
  '@storybook/addon-vitest/internal/vitest-context'
).catch(() => ({
  server: { commands: {} }
}))) as unknown as VitestBrowserContext;

const { getInitialGlobals } = server.commands;

Alternatively, ensure vitest-context.ts re-exports the required members like vitest-context-legacy.ts does by adding export * from 'vitest/browser';.

🤖 Prompt for AI Agents
In code/addons/vitest/src/vitest-plugin/test-utils.ts around lines 44-49 the
dynamic import assumes the module exports a destructurable `server` property
which breaks for Vitest 4+ (vitest-context.ts exports a named function only);
either add defensive error handling and a fallback object when importing (mirror
the pattern used in viewports.ts so the import catches failures and returns an
object with server: { commands: {} } to avoid destructure runtime errors) or
modify the Vitest 4+ module (vitest-context.ts) to re-export the expected
members (e.g., `export * from 'vitest/browser'` or explicitly re-export
`server`/commands) so the destructuring succeeds.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
code/addons/vitest/src/vitest-plugin/vitest-context.ts (1)

1-26: Unresolved: Replace version sniffing with feature detection.

A previous review comment (see above in "Comments from reviews on previous commits") suggested replacing the current version-detection approach with feature detection using try/catch on dynamic imports. This recommendation remains valid and should be addressed:

Current issues:

  1. JSON import attributes (with: { type: 'json' }) lack universal support across Node versions/bundlers
  2. The semver dependency adds unnecessary runtime overhead
  3. Version checks create maintenance burden

Recommended approach:

let _ctxPromise: Promise<VitestServerContext> | undefined;

export const getVitestBrowserContext = async (): Promise<VitestServerContext> => {
  if (_ctxPromise) return _ctxPromise;
  
  _ctxPromise = (async () => {
    try {
      return (await import('vitest/browser')) as unknown as VitestServerContext;
    } catch {
      return (await import('@vitest/browser/context')) as unknown as VitestServerContext;
    }
  })();
  
  return _ctxPromise;
};

This eliminates the semver dependency, avoids JSON import attributes, and improves performance through caching.

🧹 Nitpick comments (1)
code/addons/vitest/src/node/vitest-manager.ts (1)

167-181: Type cast suggests missing type definitions; consider extracting common invalidation logic.

The any type cast on line 170 indicates that server.moduleGraph.invalidateModule may have type mismatches. This warrants investigation:

  1. Type safety: The cast bypasses type checking. If possible, update the type definitions or use a more specific type.
  2. Code duplication: The server invalidation logic (lines 168-171) is nearly identical to the vite invalidation logic (lines 172-175). Consider extracting a helper function.

Example refactor:

private updateLastChanged(filepath: string) {
  const invalidateModules = (moduleGraph: any, filepath: string) => {
    const mods = moduleGraph.getModulesByFile(filepath);
    mods?.forEach((mod: any) => moduleGraph.invalidateModule(mod));
  };

  this.vitest!.projects.forEach(({ browser, vite, server }) => {
    if (server) {
      invalidateModules(server.moduleGraph, filepath);
    }
    if (vite) {
      invalidateModules(vite.moduleGraph, filepath);
    }
    if (browser) {
      invalidateModules(browser.vite.moduleGraph, filepath);
    }
  });
}

Alternatively, if the type cast is necessary due to Vitest API changes, add a comment explaining why.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e5c563 and f155516.

📒 Files selected for processing (4)
  • code/addons/vitest/src/node/reporter.ts (1 hunks)
  • code/addons/vitest/src/node/vitest-manager.ts (2 hunks)
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts (1 hunks)
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/src/node/reporter.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Export functions from modules when they need to be unit-tested

Files:

  • code/addons/vitest/src/node/reporter.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
code/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In application code, use Storybook loggers instead of console.* (client code: storybook/internal/client-logger; server code: storybook/internal/node-logger)

Files:

  • code/addons/vitest/src/node/reporter.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
{code/**,scripts/**}/**/*.{ts,tsx,js,jsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not use console.log, console.warn, or console.error directly unless in isolated files where importing loggers would significantly increase bundle size

Files:

  • code/addons/vitest/src/node/reporter.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts
  • code/addons/vitest/src/node/vitest-manager.ts
  • code/addons/vitest/src/vitest-plugin/vitest-context.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-13T13:33:14.659Z
Learning: Applies to test-storybooks/** : Maintain test Storybook configurations under `test-storybooks/` for E2E and visual testing scenarios
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/vitest/src/node/vitest-manager.ts
🧬 Code graph analysis (1)
code/addons/vitest/src/vitest-plugin/vitest-context.ts (1)
code/addons/vitest/src/vitest-plugin/types.ts (1)
  • VitestBrowserContext (13-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/addons/vitest/src/node/reporter.ts (1)

63-64: Good backward-compatible fix.

The optional chaining correctly guards against processTimeoutCauses being undefined in Vitest < 4, and the TODO comment makes the temporary nature of this workaround clear.

code/addons/vitest/src/vitest-plugin/vitest-context-modern.ts (1)

1-3: LGTM - Clean compatibility shim.

The re-export pattern with the documented TypeScript ignore is appropriate for handling the Vitest 3/4 compatibility layer during local development.

code/addons/vitest/src/node/vitest-manager.ts (1)

512-514: Good API simplification.

Narrowing the signature to accept only TestProject and using env.__STORYBOOK_URL__ as the detection criterion makes the logic clearer and more focused.

- 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.
Base automatically changed from yann/support-next-16 to next October 24, 2025 08:38
@yannbf yannbf changed the title Addon-Vitest: Support Vitest 4 Addon-Vitest: Extra changes for Vitest 4 Oct 24, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
code/addons/vitest/package.json (1)

87-118: Unresolved: Playwright version pinning for E2E consistency.

A previous review flagged (critical) that Playwright should be pinned to 1.52.0 in devDependencies to match the codebase-wide pinning across test-storybooks and scripts packages. Although @vitest/browser-playwright@^4.0.1 is present in devDependencies, without an explicit "playwright": "1.52.0" entry, transitive resolution may drift.

To maintain E2E consistency across all packages, add "playwright": "1.52.0" to devDependencies.

Apply this diff to add explicit Playwright pinning:

  "devDependencies": {
    "@types/istanbul-lib-report": "^3.0.3",
    "@types/micromatch": "^4.0.0",
    "@types/node": "^22.0.0",
    "@types/semver": "^7",
    "@vitest/browser-playwright": "^4.0.1",
    "@vitest/runner": "^4.0.1",
    "boxen": "^8.0.1",
    "empathic": "^2.0.0",
    "es-toolkit": "^1.36.0",
    "execa": "^8.0.1",
    "istanbul-lib-report": "^3.0.1",
    "micromatch": "^4.0.8",
    "pathe": "^1.1.2",
+   "playwright": "1.52.0",
    "picocolors": "^1.1.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "semver": "^7.6.3",
    "sirv": "^2.0.4",
    "slash": "^5.0.0",
    "tinyglobby": "^0.2.10",
    "tree-kill": "^1.2.2",
    "ts-dedent": "^2.2.0",
    "typescript": "^5.8.3",
    "vitest": "^3.2.4"
  }

After updating, run your package manager (yarn, npm, or pnpm) to update the lock file.

🧹 Nitpick comments (1)
code/addons/vitest/package.json (1)

49-50: Exports correctly configured for Vitest 3/4 compatibility support.

Build configuration properly maps both ./internal/vitest-context and ./internal/vitest-context-legacy to their source files. The vitest-context.ts implementation uses runtime semver detection to conditionally import vitest/browser (v4) or @vitest/browser/context (v3), enabling seamless support for both versions.

Note: vitest-context-modern.ts is orphaned dead code (never imported or exported) and should be removed.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87a2680 and 10e8b3e.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • code/addons/vitest/package.json (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,json,html,ts,tsx,mjs}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,jsx,json,html,ts,tsx,mjs}: Run Prettier formatting on changed files before committing
Run ESLint on changed files and fix all errors/warnings before committing (use yarn lint:js:cmd <file>)

Files:

  • code/addons/vitest/package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: daily
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/addons/vitest/package.json (1)

106-106: Verify rationale for downgrading vitest devDependency.

The devDependency for vitest was downgraded from ^4.0.1 to ^3.2.4, while peerDependencies declare support for both ^3.0.0 || ^4.0.0. This downgrade is likely intentional—testing against the latest Vitest 3 ensures backward compatibility—but clarify this design choice to confirm it aligns with the PR's Vitest 4 support objectives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

addon: vitest bug ci:daily Run the CI jobs that normally run in the daily job.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: addon-vitest install script fails because of vitest 4

4 participants