Skip to content

Addon-Vitest: Support non-ASCII project paths#34686

Open
cyphercodes wants to merge 1 commit into
storybookjs:nextfrom
cyphercodes:fix/addon-vitest-non-ascii-path
Open

Addon-Vitest: Support non-ASCII project paths#34686
cyphercodes wants to merge 1 commit into
storybookjs:nextfrom
cyphercodes:fix/addon-vitest-non-ascii-path

Conversation

@cyphercodes
Copy link
Copy Markdown
Contributor

@cyphercodes cyphercodes commented May 2, 2026

Closes #33700

What I did

  • Decode URL-encoded Vite module IDs before matching Storybook story globs, so projects in non-ASCII paths like tést still run story files through the Storybook Vitest transform.
  • Added regression coverage for the encoded path case in the addon-vitest plugin.

AI assistance: OpenAI Codex via Hermes Agent helped create this contribution.

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

No browser manual testing was needed for this path-matching fix. I ran:

  • yarn exec oxfmt --check code/addons/vitest/src/vitest-plugin/index.ts code/addons/vitest/src/vitest-plugin/index.test.ts
  • NODE_OPTIONS=--max-old-space-size=4096 yarn --cwd code lint:js:cmd addons/vitest/src/vitest-plugin/index.ts addons/vitest/src/vitest-plugin/index.test.ts
  • yarn vitest run --config code/addons/vitest/vitest.config.ts code/addons/vitest/src
  • yarn nx check addon-vitest

Documentation

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

Summary by CodeRabbit

  • Bug Fixes
    • Fixed handling of project paths and file IDs containing special characters during story transformation.
    • Improved path matching and resolution for files with non-ASCII or URL-encoded characters in their paths.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 2, 2026

📝 Walkthrough

Walkthrough

The PR adds URI decoding support to the Vitest plugin to handle non-ASCII project paths and URL-encoded story module IDs. A new decodePathForMatching helper safely decodes import IDs before path matching and transformation, with comprehensive test coverage verifying correct behavior when story module paths are URL-encoded.

Changes

URI Decoding in Vitest Plugin

Layer / File(s) Summary
Core Decoding Helper
code/addons/vitest/src/vitest-plugin/index.ts (lines 127–134)
decodePathForMatching(id) helper introduced to safely decodeURI import IDs with fallback to original string on decode failure.
Plugin Transform Integration
code/addons/vitest/src/vitest-plugin/index.ts (lines 147–148, 163, 507–513)
Component and Vitest transform hooks updated to decode ID before path resolution and pass decoded fileName to componentTransform and vitestTransform.
Test Coverage
code/addons/vitest/src/vitest-plugin/index.test.ts
Comprehensive test suite mocks Storybook internals and verifies plugin correctly transforms URL-encoded story module IDs in projects with non-ASCII paths; asserts vitestTransform is called with the decoded file path.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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.

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

3-3: 💤 Low value

vitestTransform mock should return a Promise.

Per coding guidelines, mock implementations for async functions must return a Promise. The test works correctly today because the surrounding async transform handler wraps the synchronous return, but aligning with the codebase standard avoids confusion.

♻️ Proposed fix
-const vitestTransform = vi.hoisted(() => vi.fn(() => ({ code: 'transformed code' })));
+const vitestTransform = vi.hoisted(() => vi.fn(async () => ({ code: 'transformed code' })));

As per coding guidelines, "Each mock implementation should return a Promise for async functions in Vitest tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/addons/vitest/src/vitest-plugin/index.test.ts` at line 3, The
vitestTransform mock (created via vi.hoisted and vi.fn) is returning a plain
object but should return a Promise to match async function conventions; update
the mock implementation used in vitest-plugin/index.test.ts so vi.fn(() => ({
code: 'transformed code' })) becomes an implementation that returns
Promise.resolve({ code: 'transformed code' }) (i.e., ensure vitestTransform
resolves a Promise) so the mock semantics align with the async transform
handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/addons/vitest/src/vitest-plugin/index.test.ts`:
- Line 3: The vitestTransform mock (created via vi.hoisted and vi.fn) is
returning a plain object but should return a Promise to match async function
conventions; update the mock implementation used in vitest-plugin/index.test.ts
so vi.fn(() => ({ code: 'transformed code' })) becomes an implementation that
returns Promise.resolve({ code: 'transformed code' }) (i.e., ensure
vitestTransform resolves a Promise) so the mock semantics align with the async
transform handler.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e22ebed-1e9e-46ee-a58b-3bcdd5e5357d

📥 Commits

Reviewing files that changed from the base of the PR and between f9060db and 4f85668.

📒 Files selected for processing (2)
  • code/addons/vitest/src/vitest-plugin/index.test.ts
  • code/addons/vitest/src/vitest-plugin/index.ts

@valentinpalkovic
Copy link
Copy Markdown
Contributor

Hi @cyphercodes,

Thanks for tackling this!

Two things worth considering as follow-ups:

  1. normalizePath from vite: We're calling raw path.resolve / relative, which on Windows can produce backslash-separated paths that won't compare equal to the POSIX-form ids Vite emits. The Vite docs explicitly recommend normalizePath from the vite package for this kind of comparison. The current POSIX-only test won't catch this, but it's a likely follow-up if a Windows user hits a similar non-ASCII case.

  2. Test could exercise the integration. The unit test injects the encoded id directly into the plugin, which proves the plugin handles encoding but not that Vitest is currently producing it in this scenario. Given the linked [Bug]: Vitest/Test addon does not work if non-ASCII character in path #33700 has a real-world repro, would it be feasible to add a small fixture-based integration test (project dir with é, runs vitest, asserts the story transforms)? Happy with the unit coverage either way for this PR.

@valentinpalkovic valentinpalkovic moved this from In Progress to On Hold in Core Team Projects May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: On Hold

Development

Successfully merging this pull request may close these issues.

[Bug]: Vitest/Test addon does not work if non-ASCII character in path

3 participants