Skip to content

Record what a browser-mode test loaded from the Vite module graph, so --changed skips browser tests whose inputs did not change - #18

Merged
max-blacksmith merged 4 commits into
mainfrom
devin/1794508845-browser
Nov 12, 2026
Merged

max-blacksmith merged 4 commits into
mainfrom
devin/1794508845-browser

Conversation

@max-blacksmith

@max-blacksmith max-blacksmith commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Feature + tests — a browser-mode test (test.browser.enabled) now reruns under --changed only when a module it loaded changed, instead of on every run. Vitest's own --changed gets the same records, so plain vitest --changed benefits too.

Problem

@vitest/browser never calls onTestModuleDependencies, so dependencies.json holds no record for a browser test file. Vitest's RecordedModulesResolver treats a file without a record as "always runs", and the plugin's snapshot cannot override that. For a repo such as t3code's apps/web (216 browser test files beside 356 node ones) the browser half of the suite gets no savings.

Record the browser's module graph in the plugin

The project's Vite client environment transformed every module the browser fetched, so its module graph is the record the node worker would have reported. In SnapshotRecorder.onTestModuleEnd, for a browser project only, recordBrowserDependencies (new src/browser.ts) walks project.vite.environments.client.moduleGraph from the test file and the project's setupFiles over importedModules, keeps each node's file (virtual modules like /@vitest/... have none; vitest's own dist/ is dropped, as the node collector does), and hands the list to the same call the worker RPC makes:

vitest.cache._dependencies.record(project, module.moduleId, files)

_dependencies is @internal; when a future vitest no longer exposes it the plugin warns once and browser tests fall back to always running (today's behavior).

Vitest's resolveFiles then applies its usual filter (absolute, not node_modules) and, with the module runner on, follows transformResult.deps too, so the record matches a node project's shape:

"files": { "src/dom.test.ts": { "deps": ["src/setup.ts", "src/lib/setup-lib.ts", "src/dom.test.ts", "src/lib/dom.ts", "src/lib/shared.ts"] } }

Evidence

test/fixture-browser is a two-file browser project (Playwright, headless Chromium) with a shared module and a setupFiles entry that imports its own module.

Edit Runs under --changed
nothing none (all 2 ran before this PR)
src/lib/dom.ts dom
src/lib/math.ts math
src/lib/shared.ts (imported by both) both
src/lib/setup-lib.ts (via setupFiles) both

CI and the release workflow install Chromium (npx playwright install --with-deps chromium) for this fixture.

Risks

  • Relies on vitest's internal cache._dependencies.record; a rename degrades to today's always-run with a warning, never to a wrong skip.
  • Files a browser test fetches at run time (fetch('/fixture.json')) do not pass through the module graph and are not recorded; the README caveat says so and points to the dependencies option.
  • @vitest/browser-playwright and playwright join devDependencies (test-only); CI now downloads Chromium.

Link to Devin session: https://app.devin.ai/sessions/bd00ad706b5c470c88901f0de1d26deb
Open in Devin Desktop: https://app.devin.ai/desktop/session/bd00ad706b5c470c88901f0de1d26deb?variant=devin
Requested by: @max-blacksmith


View full Proof
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need. (Staging)


View full Proof
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


🟢 Devin Review found nothing to fix · View findings · Follow Devin's work

Devin Review

… --changed can skip it

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@blacksmith-sh

blacksmith-sh Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Matches Unchanged browser tests skipped under --changed

With no edits, --changed reran both browser tests before; after, it ran none and exited 0.

Merge-base

No-edit rerun

This PR 21af8a9d

No-edit rerun

Also checked · 7 match

Matches Edits rerun only the browser tests that loaded them
Matches Default plugin mode skips browser tests too
Matches New import picked up after rerun
Matches Missing internal API falls back to always-run
Matches Test missing from the graph keeps no record
Matches User module under a vitest/dist path is recorded
Matches Fixture package.json edit reruns browser tests

Proof on 21af8a9d (from b6e7778d) · Did Proof get it right? Yes · No

View full Proof report · React 👎 or comment @codesmith dismiss this proof to dismiss

@blacksmith-staging

blacksmith-staging Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Matches Plugin selection skips unchanged browser tests

Before, both browser tests ran on every run. After, a clean tree ran none. Editing dom.ts or math.ts reran only its own test, and editing shared.ts or the setup file's import reran both.

Merge-base

Plugin selection runs

This PR 21af8a9d

Plugin selection runs

Merge-base

Recorded browser deps

This PR 21af8a9d

Recorded browser deps

Also checked · 7 match

Matches Plain vitest --changed uses the records
Matches Mixed node and browser projects
Matches Fallback when vitest hides its record
Matches No record when the test is missing from the graph
Matches User module under a vitest/dist path is tracked
Matches Filtered run keeps the full record
Matches Changed manifest reruns browser tests

Proof on 21af8a9d (from b6e7778d) · not run: Blacksmith cache backend (the snapshot and dependency records stay in the fixture's local Vite cache dir b...) · Did Proof get it right? Yes · No

View full Proof report · React 👎 or comment @codesmith dismiss this proof to dismiss

cursor[bot]

This comment was marked as resolved.

max-blacksmith and others added 2 commits November 12, 2026 19:13
… graph, rather than an empty one --changed would trust

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…s node_modules, and a repo path holding /vitest/dist/ is a user module

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot 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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@max-blacksmith
max-blacksmith merged commit 898d78b into main Nov 12, 2026
7 checks passed
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.

1 participant