Skip to content

Addon-Vitest: Improve config file detection in monorepos#33814

Merged
valentinpalkovic merged 2 commits into
nextfrom
valentin/improve-config-file-detection
Feb 12, 2026
Merged

Addon-Vitest: Improve config file detection in monorepos#33814
valentinpalkovic merged 2 commits into
nextfrom
valentin/improve-config-file-detection

Conversation

@valentinpalkovic
Copy link
Copy Markdown
Contributor

@valentinpalkovic valentinpalkovic commented Feb 9, 2026

Closes #33805

What I did

Fixed Vitest config file detection in @storybook/addon-vitest so it works correctly in monorepo sub-packages.

Problem

When using @storybook/addon-vitest inside a monorepo sub-package (e.g. ./packages/web-app), the Vitest backend fails to start with the error: "No projects found for [project-name]".

This happens because the addon's VitestManager.startVitest() searches for Vitest config files using find.any() starting from process.cwd() up to getProjectRoot(). In a monorepo, both can resolve to the monorepo root (where .git lives), so a vitest.config.ts located in the sub-package directory is never discovered. This scenario happens if storybook is called from the root with --config-dir pointing to a sub-directory.

Fix

Three changes in code/addons/vitest/src/node/vitest-manager.ts:

  1. Start config search from the package root instead of process.cwd() — The Storybook configDir (e.g. packages/web-app/.storybook) already identifies the sub-package. We derive the package root as dirname(resolve(configDir)) and pass it as the cwd to find.any(), which then traverses upward to getProjectRoot(). This ensures configs in both sub-packages and the monorepo root are found.

  2. Validate found configs contain storybookTest — When multiple config files exist in the search path, the code now reads each candidate and checks if it contains the storybookTest plugin reference. This prevents picking up unrelated Vite/Vitest configs that don't include the Storybook test plugin. The search also now includes vite.config.* files in addition to vitest.config.* and vitest.workspace.*.

  3. Improved root fallback — When no matching config is found, the Vitest root falls back to packageRoot (the sub-package directory) instead of process.cwd() (the monorepo root).

Behavior in different scenarios

Scenario Before After
Monorepo, config in sub-package Fails: "No projects found" Finds config in sub-package
Monorepo, config at root Works Works (search traverses up)
Single-package repo Works Works (packageRoot = project root)

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

Caution

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

Reproduction: https://github.com/valentinpalkovic/valentinpalkovic-turbo-repo-reproduction-no-projects-found

  1. Run pnpm i
  2. Run pnpm storybook
  3. Open Storybook and run the tests. They work as expected (canary used)
  4. Change the storybook version in all package.json's to the latest release
  5. Start Storybook and run tests. Observe test failure due to "No projects found" error

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-33814-sha-b09081a7. Try it out in a new sandbox by running npx storybook@0.0.0-pr-33814-sha-b09081a7 sandbox or in an existing project with npx storybook@0.0.0-pr-33814-sha-b09081a7 upgrade.

More information
Published version 0.0.0-pr-33814-sha-b09081a7
Triggered by @valentinpalkovic
Repository storybookjs/storybook
Branch valentin/improve-config-file-detection
Commit b09081a7
Datetime Thu Feb 12 09:03:58 UTC 2026 (1770887038)
Workflow run 21940111984

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=33814

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

Enhanced Vitest config discovery in monorepos by implementing logic that traverses from the Storybook configDir's parent directory toward the project root, searching for config files (vitest.workspace., vitest.config., vite.config.*) containing the 'storybookTest' string to determine the correct config path.

Changes

Cohort / File(s) Summary
Vitest Config Discovery Enhancement
code/addons/vitest/src/node/vitest-manager.ts
Added config discovery logic that starts from packageRoot and traverses toward project root, building a list of Vitest config filenames and searching for configs containing 'storybookTest'. Introduced readFileSync inspection to validate config relevance before selection. Updated imports to include readFileSync and resolve utilities.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • storybookjs/storybook#33712 — Implements config-detection logic for Vitest Storybook integration by searching configs for the storybookTest plugin, directly related to this config discovery enhancement.
✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link
Copy Markdown
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

🤖 Fix all issues with AI agents
In `@code/addons/vitest/src/node/vitest-manager.ts`:
- Around line 96-105: The loop over configFiles that uses find.any and then
readFileSync (within the block referencing maybe and setting
vitestWorkspaceConfig) should guard against unreadable files by wrapping the
readFileSync call in a try/catch; on error (EACCES, EISDIR, or other fs errors)
skip that candidate and continue the loop instead of throwing, ensuring
vitestWorkspaceConfig is only set when the file is successfully read and
contains 'storybookTest'. Keep the check for existsSync as-is but add the
try/catch around readFileSync and continue on failure to match existing
error-handling patterns in this module.

Comment on lines +96 to +105
for (const file of configFiles) {
const maybe = find.any([file], { cwd: packageRoot, last: getProjectRoot() });
if (maybe && existsSync(maybe)) {
const content = readFileSync(maybe, 'utf8');
if (content.includes('storybookTest')) {
vitestWorkspaceConfig = maybe;
break;
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the vitest-manager.ts file
find . -name "vitest-manager.ts" -type f

Repository: storybookjs/storybook

Length of output: 112


🏁 Script executed:

# Check the file size and read the relevant section
wc -l code/addons/vitest/src/node/vitest-manager.ts
head -150 code/addons/vitest/src/node/vitest-manager.ts | tail -80

Repository: storybookjs/storybook

Length of output: 3244


🏁 Script executed:

# Look for how readFileSync is used elsewhere in this file and error handling patterns
rg -n "readFileSync|try.*catch|existsSync" code/addons/vitest/src/node/vitest-manager.ts -A 2 -B 2

Repository: storybookjs/storybook

Length of output: 687


🏁 Script executed:

# Check for similar config discovery patterns in the vitest addon
fd "\.ts$" code/addons/vitest/src/node/ --exec rg -l "readFileSync|find.any" {} \;

Repository: storybookjs/storybook

Length of output: 110


🏁 Script executed:

# Look at the imports and overall structure to understand error handling approach
head -50 code/addons/vitest/src/node/vitest-manager.ts

Repository: storybookjs/storybook

Length of output: 2019


🏁 Script executed:

# Check if there's any error handling in similar patterns within the file
rg -n "try|catch" code/addons/vitest/src/node/vitest-manager.ts | head -20

Repository: storybookjs/storybook

Length of output: 542


🏁 Script executed:

# Verify imports to confirm readFileSync is from node:fs
head -30 code/addons/vitest/src/node/vitest-manager.ts | grep -E "import|readFileSync"

Repository: storybookjs/storybook

Length of output: 799


🏁 Script executed:

# Check if there are other config discovery patterns in the codebase that handle this
rg -B 3 -A 3 "find\.any.*readFileSync|existsSync.*readFileSync" code/addons/vitest/

Repository: storybookjs/storybook

Length of output: 334


Guard config discovery against unreadable files.

The existsSync check only verifies file existence, not readability. A file can become unreadable between the existence check and readFileSync call (race condition, permission change), or fail with EACCES/EISDIR. Wrap the read in try/catch to gracefully skip unreadable candidates and continue the search, aligning with the error handling patterns already used throughout this file.

      if (maybe && existsSync(maybe)) {
-       const content = readFileSync(maybe, 'utf8');
-       if (content.includes('storybookTest')) {
-         vitestWorkspaceConfig = maybe;
-         break;
-       }
+       try {
+         const content = readFileSync(maybe, 'utf8');
+         if (content.includes('storybookTest')) {
+           vitestWorkspaceConfig = maybe;
+           break;
+         }
+       } catch {
+         // Skip unreadable config candidates and continue searching
+       }
      }
🤖 Prompt for AI Agents
In `@code/addons/vitest/src/node/vitest-manager.ts` around lines 96 - 105, The
loop over configFiles that uses find.any and then readFileSync (within the block
referencing maybe and setting vitestWorkspaceConfig) should guard against
unreadable files by wrapping the readFileSync call in a try/catch; on error
(EACCES, EISDIR, or other fs errors) skip that candidate and continue the loop
instead of throwing, ensuring vitestWorkspaceConfig is only set when the file is
successfully read and contains 'storybookTest'. Keep the check for existsSync
as-is but add the try/catch around readFileSync and continue on failure to match
existing error-handling patterns in this module.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Feb 10, 2026

View your CI Pipeline Execution ↗ for commit b09081a

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ✅ Succeeded 5m 42s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-12 10:56:43 UTC

@valentinpalkovic valentinpalkovic added the patch:yes Bugfix & documentation PR that need to be picked to main branch label Feb 12, 2026
@valentinpalkovic valentinpalkovic merged commit d7c87fa into next Feb 12, 2026
126 of 129 checks passed
@valentinpalkovic valentinpalkovic deleted the valentin/improve-config-file-detection branch February 12, 2026 10:51
valentinpalkovic added a commit that referenced this pull request Feb 17, 2026
…le-detection

Addon-Vitest: Improve config file detection in monorepos
(cherry picked from commit d7c87fa)
@github-actions github-actions Bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

addon: vitest bug ci:normal patch:done Patch/release PRs already cherry-picked to main/release branch patch:yes Bugfix & documentation PR that need to be picked to main branch

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: Addon-vitest fails to find projects in monorepo sub-packages

2 participants