feat(cli): npx vitest-native init | doctor | migrate#75
Open
danfry1 wants to merge 3 commits into
Open
Conversation
The docs previously asked migrating users to be the codemod: the jest-compat
config block was copy-pasted across four doc pages, environment problems
(missing babel preset, RNTL 14 on Node < 22.13, absent peers) surfaced as raw
runtime failures, and the project's own migration-friction audit found ~70%
of Jest-migration friction to be mechanically mappable configuration.
- init: writes a ready-to-run config; --jest-compat emits the migration
guide's canonical block (single source of shape); refuses to overwrite
without --force; .mts for TS projects, .mjs otherwise.
- doctor: read-only diagnosis — Node floor, RNTL 14 ⇄ Node 22.13, required
peers against supported ranges (per-major Vite floors included), the
engine 'auto' resolution and its reason, every auto-detected preset, Expo
presence with known-limits pointer, config presence. Non-zero exit on
blocking problems so it can gate CI setup.
- migrate: analyzes package.json#jest / jest.config.{js,cjs,json} and
reports key-by-key: mapped automatically (setup files, path aliases,
transformIgnorePatterns allowlist extraction → transform: [...],
timeouts, clear/reset/restoreMocks), covered-by-presets (deletable
__mocks__ and setup lines), needs-attention (regex mappers, fake timers,
unknown keys), and dropped keys — ending with a complete suggested
config. Dry-run by default; --write saves it. ts/mjs/function configs
are reported as unloadable rather than guessed at.
Implementation reuses the plugin's own building blocks (detectEngine,
validatePeerDependency, AUTO_DETECT_PRESETS) and is vitest-free at module
load (runs via npx). Ships as dist/cli.mjs via the package bin; the
packed-tarball consumer suite runs doctor and migrate end-to-end.
…d extraction fixes
Pre-PR review findings, two of them blockers:
- migrate's alias emission produced relative Vite aliases ('@' → './src'),
which Vite resolves relative to the IMPORTER — broken for any test not at
the project root. Aliases now emit absolute paths via
fileURLToPath(new URL(..., import.meta.url)) with the import added to the
suggested config; mappers that still carry regex syntax after the strip go
to needs-attention instead of emitting something half-right.
- A test derived a filesystem path from URL.pathname, which yields /C:/…
on Windows and would have failed the Windows CI leg; fileURLToPath now.
- transformIgnorePatterns extraction: entries with capturing groups
((jest-)?react-native) previously stripped into fabricated package names;
they are now surfaced as needs-attention, the raw pattern is always
echoed in the report, and the lookahead-body regex no longer closes early
on a leading nested group.
- Jest config precedence now matches Jest (config file wins over
package.json#jest); collectCoverageFrom is actually emitted as
test.coverage.include; --root before the command dispatches correctly;
explicit --help exits 0; the dead setupFilesAfterEach branch is gone.
- The peer-requirements table is extracted to src/peer-requirements.ts and
shared by plugin startup validation and doctor, so they cannot drift.
CodeQL (js/redos): the lookahead-body regex used [^()]+ inside a star — the classic nested-quantifier shape with exponential backtracking on unclosed input like '(?!aaaa…'. Single-character alternatives keep the repetition unambiguous and linear while preserving the no-early-close property for leading nested groups. Verified: 50k-char unclosed input resolves in milliseconds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The project's own migration-friction audit found ~70% of Jest-migration friction to be mechanically mappable configuration — but the docs asked the user to be the codemod: the jest-compat config block was copy-pasted across four doc pages, and environment problems (missing Babel preset, RNTL 14 on Node < 22.13, absent peers) surfaced as raw runtime failures with no diagnosis.
Change
A package bin (
dist/cli.mjs, vitest-free at module load) with three commands:init— writes a ready-to-run config (.mtsfor TS projects,.mjsotherwise; refuses to overwrite without--force).--jest-compatemits the migration guide's canonical block, making the CLI the single source of that shape.doctor— read-only diagnosis: Node floor, the RNTL 14 ⇄ Node 22.13 interaction, required peers against the supported ranges (table shared with the plugin's startup validation viasrc/peer-requirements.ts, so they cannot drift), which engineautoresolves to and why, every auto-detected preset, Expo presence with known-limits pointer, and config presence. Exits non-zero on blocking problems so it can gate CI setup.migrate— analyzesjest.config.{js,cjs,json}orpackage.json#jest(Jest's own precedence) and reports key-by-key: mapped automatically (setup files, path aliases emitted as absolute paths,transformIgnorePatternsallowlist extraction →transform: [...], timeouts, coverage include, mock-hygiene flags), covered by presets — delete (manual__mocks__and RN setup lines), needs attention (regex mappers, capturing-group allowlist entries, fake timers, unknown keys — surfaced rather than guessed at; the rawtransformIgnorePatternsis always echoed), and dropped. Ends with a complete suggested config;--writesaves it. Test files are never edited —jestMockTransform()handles top-leveljest.mockat runtime.Review
Independently adversarially reviewed pre-PR. Both blockers it found are fixed: a Windows-fatal
URL.pathnamepath derivation in a test, and — the important one — the alias emission produced relative Vite aliases, which Vite resolves per-importer; aliases now emit absolutefileURLToPath(new URL(...))expressions. Also incorporated: Jest-matching config precedence, honest handling of capturing-group allowlist entries (previously stripped into fabricated package names),--root-before-command dispatch,--helpexit 0, coverage emission, and the shared peer table. The reviewer verified the bin shims dispatch correctly on POSIX and Windows and that the consumer smoke passes.Tests
15 unit tests (dispatch, init variants and guards, doctor including the RNTL/Node conflict and a live self-check, migrate extraction/report/write, capturing-group and no-config cases) plus the packed-tarball consumer suite now running
npx vitest-native doctorandmigrateend-to-end. Website gets a CLI page; changeset is minor (new feature).Full gate: mock suite 1307, consumers green, lint/format/typecheck clean.