Skip to content

fix(browser-playwright): clear stale mock routes for duplicate URLs#10040

Open
teee32 wants to merge 1 commit intovitest-dev:mainfrom
teee32:fix/browser-manual-mock-route-leak
Open

fix(browser-playwright): clear stale mock routes for duplicate URLs#10040
teee32 wants to merge 1 commit intovitest-dev:mainfrom
teee32:fix/browser-manual-mock-route-leak

Conversation

@teee32
Copy link
Copy Markdown

@teee32 teee32 commented Apr 2, 2026

Description

Problem
When two mocked ids resolve to the same module URL in Browser Mode, the Playwright provider registers two routes for the same logical module but only keeps the latest predicate reference. Cleanup then removes only the last route, so an older manual mock can leak into the next spec file.

Reproduction / Observation
Resolves #9957.

The new test/browser/fixtures/manual-mock-alias-leak fixture reproduces this with two spec files:

  1. probe.spec.ts registers manual mocks for ~/modal and ./modal, which both resolve to the same file.
  2. target.spec.ts imports ~/modal without mocking it.

Before this change, the second spec could hit a stale route from the first spec and fail with [birpc] rpc is closed, cannot call "resolveManualMock".

Root cause
packages/browser-playwright/src/playwright.ts tracks predicates by sessionId:url, but duplicate registrations for the same resolved URL overwrite the stored predicate while leaving the previous Playwright route installed. delete() and clear() can then only unroute the latest handler, so the earlier manual mock survives into the next file.

Change

  • store per-session mock URLs in a Set instead of an array
  • normalize URLs before unregistering them
  • unroute any existing predicate before registering a new route for the same resolved URL
  • add a browser fixture and regression test that cover two ids resolving to one manual mock URL across spec files

Why this fix
The provider already treats sessionId + resolved URL as the identity for a mock route. Replacing any existing route for that identity is the smallest change that makes cleanup reliable without changing mock resolution semantics.

Risk
The change is limited to Playwright Browser Mode route bookkeeping. It only affects duplicate registrations for the same resolved URL within one session; other providers and non-duplicate routes are unchanged.

Validation

  • pnpm --filter @vitest/browser-playwright run build
  • BROWSER=chromium pnpm -C test/browser run test-fixtures --root ./fixtures/manual-mock-alias-leak
  • BROWSER=chromium pnpm -C test/browser exec vitest --no-watch --config=vitest.config.unit.mts specs/mocking.test.ts -t "manual mocks do not leak across browser spec files when the same module is mocked via different ids"
  • BROWSER=chromium pnpm -C test/browser exec vitest --no-watch --config=vitest.config.unit.mts specs/mocking.test.ts
  • pnpm exec eslint --no-warn-ignored packages/browser-playwright/src/playwright.ts test/browser/specs/mocking.test.ts

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.

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

netlify bot commented Apr 2, 2026

Deploy Preview for vitest-dev ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 3fc6a83
🔍 Latest deploy log https://app.netlify.com/projects/vitest-dev/deploys/69cdcf2c86b2240008977262
😎 Deploy Preview https://deploy-preview-10040--vitest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@hi-ogawa
Copy link
Copy Markdown
Collaborator

hi-ogawa commented Apr 2, 2026

Looks like CI is failing with new tests. Can you look into it?

@hi-ogawa hi-ogawa added the maybe automated User is likely an AI agent, or the content was generated by an AI assistant without user control label Apr 2, 2026
@teee32
Copy link
Copy Markdown
Author

teee32 commented Apr 2, 2026

I checked the failed jobs. They all timed out on the new browser mocking regression test, but I couldn't reproduce that timeout locally on the current HEAD. I reran the closest commands serially with the full Playwright browser matrix and they passed:\n\n- \n- \n- \n- \ (the new mocking test passed there as well)\n\nI don't have permission to rerun the upstream Actions jobs from the fork, so the next useful step is probably to rerun the failed browser jobs once to see if the timeout reproduces on CI.

@teee32
Copy link
Copy Markdown
Author

teee32 commented Apr 2, 2026

I checked the failed jobs. They all timed out on the new browser mocking regression test, but I couldn't reproduce that timeout locally on the current HEAD. I reran the closest commands serially with the full Playwright browser matrix and they passed:

  • pnpm -C test/browser run test-fixtures --root ./fixtures/manual-mock-alias-leak
  • pnpm -C test/browser exec vitest --no-watch --config=vitest.config.unit.mts specs/mocking.test.ts -t "manual mocks do not leak across browser spec files when the same module is mocked via different ids"
  • pnpm -C test/browser exec vitest --no-watch --config=vitest.config.unit.mts specs/mocking.test.ts
  • pnpm -C test/browser run test:playwright (the new mocking test passed there as well)

I don't have permission to rerun the upstream Actions jobs from the fork, so the next useful step is probably to rerun the failed browser jobs once to see if the timeout reproduces on CI.

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

Labels

maybe automated User is likely an AI agent, or the content was generated by an AI assistant without user control

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Browser Mode leaks a manual mock across spec files when the same module is mocked via two ids

2 participants