Skip to content

feat(plugin-js): js_test driver, per-test-file granularity - #364

Draft
raphaelvigee wants to merge 1 commit into
raphaelvigee/feat-plugin-js-m3-typecheckfrom
raphaelvigee/feat-plugin-js-m4-test
Draft

feat(plugin-js): js_test driver, per-test-file granularity#364
raphaelvigee wants to merge 1 commit into
raphaelvigee/feat-plugin-js-m3-typecheckfrom
raphaelvigee/feat-plugin-js-m4-test

Conversation

@raphaelvigee

@raphaelvigee raphaelvigee commented Aug 5, 2026

Copy link
Copy Markdown
Member

M4 of the JS/TS heph plugin plan (part 4/6 of the stack).

A cacheable js_test ManagedDriver with one target per test file (vitest default, jest alt via a single testrunner config option), fed by the M2/M3 import graph — the differentiator over Turborepo/Nx, which never get finer than per-package task caching.

  • Per-test-file Input scoping: the test file's own runtime-transitive closure (BFS over ImportGraph::runtime_edges, bounded to the owning package), third-party deps resolved via the same lockfile-driven mechanism js_install/js_typecheck use, and the resolved test-runner config.
  • Runner-config discovery covers vitest's own fallback (vite.config.*) and jest's package.json "jest" field, not just the dedicated config filenames.

Reviewed by feature-quality/code-quality/hermeticity. Three BLOCKERs found and fixed: a real sandbox escape — a js_test addr's file= argument accepted an absolute path or a ..-escape with no validation, letting a target read/exec outside the workspace and sandbox entirely (fixed at both Provider::get and defensively again in the driver's run()); vitest/jest config-referenced files (setupFiles, globalSetup, a shared base config) were untracked, so editing one didn't bust the cache of every dependent test; and the primary runner-config file itself could go undiscovered for vite.config.*/package.json-jest-field layouts. Each has a regression test.

Explicitly deferred: per-test-file Provider::get rebuilding the whole package's import graph from scratch (fixed later in the stack); the cross-package one-hop trim risking a stale test-pass cache hit for a barrel-file re-export; test-runner-specific alias resolution.

Test plan

  • cargo build -p plugin-js -p plugin-js-cdylib
  • cargo test -p plugin-js
  • cargo clippy -p plugin-js -p plugin-js-cdylib --all-targets -- -D warnings
  • cargo fmt --check -p plugin-js -p plugin-js-cdylib

Stack created with GitHub Stacks CLIGive Feedback 💬

M4 of the JS/TS plugin: a cacheable js_test ManagedDriver with one target
per test file (vitest default, jest alt via a single testrunner config
option), fed by the M2/M3 import graph rather than package-level caching —
the differentiator the design doc calls out over Turborepo/Nx, which never
get finer than per-package task caching.

- Per-test-file Input scoping: the test file's own runtime-transitive
  closure (BFS over ImportGraph::runtime_edges, bounded to the owning
  package), third-party deps resolved via the same lockfile-driven
  mechanism js_install/js_typecheck use (no ambient node_modules
  dependency, per the M3 lesson), and the resolved test-runner config.
- Runner-config discovery covers vitest's own fallback (vite.config.*) and
  jest's package.json "jest" field, not just the dedicated config
  filenames.

Reviewed by feature-quality/code-quality/hermeticity. Three BLOCKERs found
and fixed: a js_test addr's file= argument accepted an absolute path or a
`..`-escape with no validation, letting a target read/exec outside the
workspace and sandbox entirely (fixed at both Provider::get and
defensively again in the driver's run()); vitest/jest config-referenced
files (setupFiles, globalSetup, a shared base config reached via a
relative import) were untracked, so editing one didn't bust the cache of
every test that depends on it; and the primary runner-config file itself
could go undiscovered for the vite.config.*/package.json-jest-field
layouts. Each has a regression test.

Explicitly deferred (named, not silent): per-test-file Provider::get
rebuilds the whole package's import graph from scratch rather than
caching it once per package (a real warm-cache-path cost); the
cross-package one-hop trim now risks a stale test-pass cache hit, not
just a missed diagnostic, for a barrel-file re-export; test-runner-specific
alias resolution (vitest resolve.alias, jest moduleNameMapper) isn't fed
into the resolver.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M3wZfyPsG8stfRQuybLRjN
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