Skip to content

fix: fix importOriginal with optimizer and query import#10469

Merged
hi-ogawa merged 13 commits into
vitest-dev:mainfrom
davidhwilliams:fix-9887
Jun 4, 2026
Merged

fix: fix importOriginal with optimizer and query import#10469
hi-ogawa merged 13 commits into
vitest-dev:mainfrom
davidhwilliams:fix-9887

Conversation

@davidhwilliams

@davidhwilliams davidhwilliams commented May 27, 2026

Copy link
Copy Markdown
Contributor

Description

original ocmment

Fxes a bug where removeQuery incorrectly strips out the leading ? parameter boundary symbol when purging internal runtime flags (like _vitest_original), leaving an orphaned & boundary behind. When a URL contains multiple query parameters (e.g., file.js?_vitest_original&v=12345), removing the first parameter results in an invalid string format (file.js&v=12345). The module evaluator subsequently treats the query parameter as a literal extension on disk, throwing an ERR_MODULE_NOT_FOUND runtime error.

This fix ensures that if a leading ? is stripped but subsequent & parameters remain, the first remaining ampersand is properly converted back into a ? query parameter delimiter.

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. If the feature is substantial or introduces breaking changes without a discussion, PR might be closed.
  • Ideally, include a test that fails without this PR but passes with it.
  • Please, don't make changes to pnpm-lock.yaml unless you introduce a new test example.
  • Please check Allow edits by maintainers to make review process faster. Note that this option is not available for repositories that are owned by Github organizations.

Tests

  • Run the tests with pnpm test:ci.

Documentation

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs command.

Changesets

  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.

@netlify

netlify Bot commented May 27, 2026

Copy link
Copy Markdown

Deploy Preview for vitest-dev ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 61a30d6
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/6a20c6b727d07f0008d24fdb
😎 Deploy Preview https://deploy-preview-10469--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@hi-ogawa hi-ogawa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please add integration test.

@davidhwilliams

Copy link
Copy Markdown
Contributor Author

Hi @hi-ogawa, I'd be happy to add one

I couldn't find an existing test suite that directly covers this scenario or usage. Could you point me toward the preferred location for this integration test, along with maybe an example of a similar test you're looking for please? Thank you

@hi-ogawa

Copy link
Copy Markdown
Collaborator

For example, there's an integration test with optimzeDeps where we run fixture like this

const { errorTree, stderr } = await runVitest({
root: './fixtures/optimize-deps',
pool,
})

export default defineConfig({
optimizeDeps: {
include: ["@test/test-dep-url"],
},

@davidhwilliams

Copy link
Copy Markdown
Contributor Author

Added integration test. The test fails on the old code with the exact issue reported ERR_MODULE_NOT_FOUND and now passes with the fix

@davidhwilliams davidhwilliams requested a review from hi-ogawa May 30, 2026 00:11
@hi-ogawa hi-ogawa requested review from hi-ogawa and removed request for hi-ogawa May 30, 2026 08:36
@hi-ogawa

Copy link
Copy Markdown
Collaborator

Can you test optmizeDeps scneario that reproduced the issue previously?

@davidhwilliams

Copy link
Copy Markdown
Contributor Author

I apologize i misunderstood. I updated the optimizeDeps test suite to include a new test. This new test uses the same vitest.config as the others which includes using optimizeDeps.include and test.deps.optimizer.client which is the scenario thats specified in the original ticket.

The test uses vi.mock along with importOriginal which is also the scenario specified in the ticket. I confirmed the test does fail with the old code and pass with my changes.

I removed the other test i had added but i can add it back if you'd like though i think only one is necessary

@hi-ogawa hi-ogawa removed their request for review June 3, 2026 08:54
@hi-ogawa hi-ogawa self-assigned this Jun 3, 2026
@hi-ogawa hi-ogawa changed the title fix: correctly format query string when removing first parameter (fix: #9887) fix: fix importOriginal with optimizer and query import Jun 3, 2026
Comment on lines +22 to +23
.replace(new RegExp(`([?&])${queryToRemove}(?:&|$)`), '$1')
.replace(trailingSeparatorRE, '')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It looks like Claude and Me hallucinated bad removeQuery in #9772. Now I ported the one from Vite that does handles the multiple queries properly.

Copilot AI left a comment

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.

Pull request overview

Fixes a regression where importOriginal/vi.importActual could produce invalid module IDs when stripping Vitest’s internal _vitest_original flag from URLs that also include optimizer/version query parameters, leading to ERR_MODULE_NOT_FOUND (issue #9887).

Changes:

  • Adjust removeQuery in the module runner to correctly remove _vitest_original without leaving malformed query separators.
  • Add a unit test asserting importOriginal preserves query parameters (e.g. ?raw).
  • Add an e2e fixture/test covering mocking behavior with SSR optimizer + (noExternal/external) dependency permutations.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/unit/test/mocking/import-actual-query.test.ts New unit test ensuring importOriginal works with import IDs containing query (?raw).
test/unit/test/mocking/import-actual-query-target.ts Target module used by the new unit test.
test/tsconfig.json Adds vite/client types so query-suffixed imports (e.g. ?raw) typecheck in tests.
test/e2e/test/optimize-deps-mock.test.ts New e2e test runner asserting the new optimize-deps mock fixture passes across pools.
test/e2e/package.json Adds test-dep-simple2 to e2e workspace dependencies for the new fixture.
test/e2e/fixtures/optimize-deps-mock/vitest.config.ts New fixture config exercising SSR optimizer behavior in the mocked-deps scenario.
test/e2e/fixtures/optimize-deps-mock/basic.test.ts New fixture test mocking optimized + non-optimized deps and validating resolution behavior.
test/e2e/deps/dep-simple2/package.json Adds a simple ESM dependency used by the new e2e fixture.
test/e2e/deps/dep-simple2/index.js Implementation for test-dep-simple2.
pnpm-lock.yaml Lockfile update for the new local e2e dependency.
packages/vitest/src/runtime/moduleRunner/utils.ts Updates query manipulation logic used when stripping _vitest_original during module fetch.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread packages/vitest/src/runtime/moduleRunner/utils.ts
@hi-ogawa hi-ogawa merged commit 6a3bb02 into vitest-dev:main Jun 4, 2026
16 of 18 checks passed
@davidhwilliams davidhwilliams deleted the fix-9887 branch June 4, 2026 23:48
@tomasz-megaport

Copy link
Copy Markdown

Thanks for fixing this! Would it be possible to backport to the 4.1.x line? This still reproduces on the latest published releases - vitest@4.1.8 and vitest@5.0.0-beta.4 (with vite@8.0.16), and it's pool-independent (threads/forks/vmThreads).

It blocks deps.optimizer + vi.mock(mod, async (importOriginal) => ({ ...await importOriginal() })) for any optimized dep (a common pattern for partially mocking a component library), with ERR_MODULE_NOT_FOUND on a malformed deps/<dep>.js&v=<hash> URL.

Minimal config that triggers it:

// vitest.config.ts
export default defineConfig({
  optimizeDeps: { include: ['@scope/ui'] },
  test: { deps: { optimizer: { client: { enabled: true, include: ['@scope/ui'] } } } },
})
// a spec doing: vi.mock('@scope/ui', async (io) => ({ ...await io(), x: vi.fn() })) -> ERR_MODULE_NOT_FOUND

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vi.mock importOriginal causes ERR_MODULE_NOT_FOUND with &v=<hash> suffix appended to path in 4.1.0 (regression from 4.0.x)

4 participants