
Migrate To Rstest
- 303 installs
- 86 repo stars
- Updated August 4, 2026
- rstackjs/agent-skills
Use migrate-to-rstest for development tasks
About
migrate-to-rstest: A skill for development. This provides functionality for development workflows.
- migrate-to-rstest
Migrate To Rstest by the numbers
- 303 all-time installs (skills.sh)
- +15 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,341 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/rstackjs/agent-skills --skill migrate-to-rstestAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 303 |
|---|---|
| repo stars | ★ 86 |
| Last updated | August 4, 2026 |
| Repository | rstackjs/agent-skills ↗ |
What it does
Use migrate-to-rstest for development tasks
Files
Migrate to Rstest
Goal
Migrate Jest/Vitest tests and config to Rstest with minimal behavior changes. Use the current Rstest migration docs for exact mappings; this skill adds scope, dependency, and cleanup guardrails.
Workflow
1. Detect runner and scope (references/detect-test-framework.md). 2. Run dependency/version gates (references/dependency-install-gate.md). 3. Read only the needed deltas: Jest, Vitest, and/or global API replacement. 4. Migrate scripts/config/setup before tests; prefer adapters or Rsbuild/Rspack config fixes before editing test bodies. 5. Validate discovery/types/run, fixing failures in this order: dependency skew, config/resolver, setup/env/coverage, mocks/timers/snapshots, test bodies. 6. After the scope is green, remove only scope-local legacy files and devDeps no remaining scope uses. 7. Summarize changes, kept legacy files, unsupported fields, and TODOs.
Guardrails
- Keep the smallest viable scope; do not broaden a monorepo migration or bulk-rewrite tests when config/setup fixes are plausible.
- Do not change production behavior, assertions, test names, scenarios, or coverage thresholds to make migration pass.
- No
jest/vishims or aliases; rewrite call sites to Rstest APIs (references/global-api-migration.md). - Do not silently drop unknown config fields; verify or report them as unsupported.
High-risk Rstest deltas
rstest/rstest runis single-run; watch mode isrstest --watchorrstest watch.globalsdefaults tofalse; if globals remain, setglobals: trueand add@rstest/core/globalstypes.- Rstest runs on Rsbuild/Rspack. Use
references/dependency-install-gate.mdfor latest-only APIs, coverage providers, adapters, plugins, and toolchain-version fallbacks.
Escalate before large edits
If the next fix requires many test edits or production source changes, stop and report: why smaller fixes failed, options, risks, and the recommended path.
Dependency Install Gate
Use this reference when running the dependency install gate step of the migration workflow.
Quick path
Use the repo's native package manager; do not add a detector package. Pick it from packageManager, then lock files (pnpm-lock.yaml, yarn.lock, package-lock.json, npm-shrinkwrap.json, bun.lock, bun.lockb), then CI/workspace hints.
After adding @rstest/core, verify through a local-only path: e.g. pnpm exec rstest -h, a migrated test script, or ./node_modules/.bin/rstest -h for npm-only repos. Avoid commands that can fetch a remote rstest package.
Dependency decisions
Install only what the migrated scope needs: @rstest/core, one capability-supported coverage provider if coverage is enabled, and an adapter only when the existing Rsbuild/Rslib/Rspack config and peer ranges support it.
Keep Jest/Vitest and legacy coverage packages until the migrated scope is green. Remove them only during cleanup and only if no other scope still uses them. Do not add multiple Rstest coverage providers for one final scope unless the repo intentionally keeps multiple coverage modes.
Version and capability gate
Before debugging test failures, choose a compatible Rstest line and avoid latest-only config on older targets:
- Latest Rstest needs Node
^20.19.0 || >=22.12.0and the Rsbuild/Rspack 2.x ecosystem. For Rsbuild/Rspack 1.x or older Node projects, use a compatible older line such as Rstest 0.8.x unless the user accepts a toolchain upgrade. - If the target line lacks a needed feature, either use the fallback or ask whether to upgrade first.
- Prefer config-level fallbacks on older targets: plain project objects,
output.externals/aliases/manual config, Istanbul coverage, config/projects for env splits, explicit/manual mocks, configpool.maxWorkers, or manual Rspack config. - Treat
defineInlineProject,output.bundleDependencies,detectAsyncLeaks, V8 coverage, file-level env comments, newer mock helpers, CLI--pool.maxWorkers, and@rstest/adapter-rspackas latest-line features unless target docs/types prove support. - Choose Rsbuild plugins and Rstest adapters by peer dependency compatibility, not package-name major equality. In monorepos, check root and package-level overrides/resolutions, lockfile entries, and nested package managers for duplicate majors.
Inspect with the repo-native manager across workspaces (for example pnpm -r list ... --depth Infinity, or npm ls --all plus filtering). If errors mention config schema, plugin hooks, compiler mismatch, missing plugin APIs, or peer conflicts, fix dependency versions first; do not rewrite tests to hide toolchain skew.
Blocked mode
If install/check fails, stop broad edits. Do not mix package managers or fake a migration without a runnable local rstest binary unless the user accepts a config-only patch.
Report the failed command, error class, chosen package-manager signal, files already changed, next command, and resume point.
Detect Test Framework
Use this reference to decide the migration path and scope.
Detection signals
Jest signals
jestindependenciesordevDependenciesjest.config.*existspackage.jsoncontains ajestconfig block- test scripts use
jest - test code imports from
@jest/globalsor usesjest.APIs - Jest-only packages such as
ts-jest,babel-jest,jest-environment-jsdom,identity-obj-proxy,@types/jest,jest-junit
Vitest signals
vitestindependenciesordevDependenciesvitest.config.*existsvite.config.*contains atestblock for Vitestvitest.workspace.*exists- test scripts use
vitest,vitest run, orvitest --run - test code imports from
vitest(vi,vitest,describe,it,expect) - Vitest-only packages such as
@vitest/coverage-v8,@vitest/coverage-istanbul,@vitest/ui
Rstack integration signals
- Existing
rslib.config.*,rsbuild.config.*, or Rspack/Rsbuild aliases/plugins usually means adapters or config ports should be tried before test edits. rspack.config.*can use@rstest/adapter-rspackonly on a compatible Rspack 2.x line; for Rspack 1.x / Rstest 0.8.x, port needed settings manually.@rsbuild/core,@rspack/core,@rslib/core,@rsbuild/plugin-*,overrides,resolutions, orpnpm.overridesmust feed into the dependency gate before choosing Rstest/adapters/plugins.
Browser / DOM signals
- Jest
testEnvironment: 'jsdom', Vitestenvironment: 'jsdom'/happy-dom, or file-level environment comments. - React/Vue Testing Library setup files.
@testing-library/jest-dom/vitestshould be replaced with direct matcher registration in Rstest setup.
Decision rules
- If only one runner is detected, migrate that runner path.
- If both are detected, treat as mixed mode and migrate one scope at a time (package/suite/project).
- Prefer migrating the currently CI-critical or higher-failure scope first.
- Keep both legacy runners until each migrated scope is green on Rstest.
- Choose the Rstest target line with the dependency gate before changing adapter/plugin versions.
- In monorepos, choose the smallest runnable scope that has its own package/config/test script. Do not migrate unrelated packages just because they share a root lockfile.
- If the root config is only a project/workspace aggregator, preserve that role: Rstest root
projectsconfig is not itself a test project unless the root is explicitly included as a project.
Global API Migration
Use this reference when tests rely on globally available test APIs (Jest's jest.<api>, or Vitest's vi.<api> / vitest.<api> under globals: true).
For identifier mapping (jest. / vi. / vitest. -> Rstest equivalents), see the official guides:
- Jest: https://rstest.rs/guide/migration/jest.md (see "Test API")
- Vitest: https://rstest.rs/guide/migration/vitest.md (see "Test API" and "Global APIs")
The rules below are skill-side enforcement on top of that mapping.
Mapping policy
- Prefer imports from
@rstest/core; use globals only when preserving global-style tests (globals: trueplus@rstest/core/globalstypes). - Rstest globals include test APIs, hooks,
rs, andrstest. Preferrsfor migration consistency.
Red lines
1. No shims. All forms below leave the migration incomplete and must be rejected in every test and setup file:
globalThis.vi = rs;/global.jest = rs;(direct global aliasing)const vi = rs;/const jest = rs;(local rebinding)import { rs as vi } from '@rstest/core';/import { rs as jest } from '@rstest/core';(aliased named import)
Fix at every call site instead. Do not propose a shim "just to keep the diff small" - it hides whether the migration actually happened, blocks IDE refactors, and silences future deprecation warnings.
2. No test-name mutation. When rewriting vi. / jest. / vitest., only replace identifiers that precede a property access and eventual call expression. After every batch edit, grep test declarations to confirm no name string was rewritten:
rg -n "(describe|it|test)\\(" --glob '*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'Test names are stable identifiers, not labels for the new API.
3. No mixed local aliases. Avoid mixing vi and rs, or jest and rs, in the same migrated file. If you touch a file, migrate all framework utility calls in that file.
Safer replacement workflow
1. Search first:
rg -n "\\b(vi|vitest|jest)\\s*\\." --glob '*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}'2. Replace only code identifiers, not arbitrary strings or snapshots. 3. Update imports from vitest / @jest/globals to @rstest/core as needed. 4. Run the search again; the only acceptable leftovers are comments documenting the migration or untouched legacy scopes. 5. If globals: true remains, verify TypeScript sees @rstest/core/globals.
Jest Migration Deltas
Use this reference when the current framework is Jest.
Source of truth
Use the official guide for exact field/API mappings:
https://rstest.rs/guide/migration/jest.md
When local docs are available, prefer the checked-out source, for example website/docs/en/guide/migration/jest.mdx.
High-signal deltas
- Scripts:
jest->rstest;--watch/--watchAll->rstest --watch;--runInBand->--pool.maxWorkers 1only when supported, otherwise configpool.maxWorkers: 1; Jest-wmeans workers, but Rstest-wmeans watch. - Config: create
rstest.config.tswithdefineConfigfrom@rstest/core. Map every important Jest field through the official guide; do not silently drop unknown fields. - Transforms: remove
preset,ts-jest, and mosttransformconfig where possible. Rstest uses SWC by default; use version-supported SWC/output/Rsbuild plugin config only when needed. - Setup: merge Jest
setupFilesandsetupFilesAfterEnvinto RstestsetupFilesbecause Rstest setup runs after framework registration. - Globals/APIs:
@jest/globals->@rstest/core;jest.<api>->rs.<api>. If globals remain, setglobals: trueand add@rstest/core/globalstypes. - Async tests:
donecallback tests are unsupported; convert to Promise orasync/await. - Hooks:
beforeEach/beforeAllreturn values are cleanup functions in Rstest. Wrap setup-only arrow expressions in braces when needed. - Environment:
testEnvironmentOptionsbecomestestEnvironment: { name, options }. File-level env comments are latest-only; older targets should split env-specific files into config/projects. - CJS mocking: use
rs.mockRequire()for code paths usingrequire(). - Coverage: install a Rstest provider supported by the target version. Jest
babelmaps to Istanbul; Jestv8maps to V8 only when thedependency-install-gate.mdcapability gate allows it.
Jest-specific enforcement
1. Delete scope-local jest.config.*, jest.setup.*, and companion jest.*.ts only after the migrated scope is green. Drop shared Jest devDeps only after no scope still uses Jest. 2. Defer snapshot re-recording until all non-snapshot failures are fixed. Jest : snapshot key separators become Rstest >, so early rstest -u creates noisy churn. 3. Review snapshot diffs by body, not key churn. Separator-only key renames are formatting; body changes are behavior signals.
Vitest Migration Deltas
Use this reference when the current framework is Vitest.
Source of truth
Use the official guide for exact field/API mappings:
https://rstest.rs/guide/migration/vitest.md
When local docs are available, prefer the checked-out source, for example website/docs/en/guide/migration/vitest.mdx.
High-signal deltas
- Scripts:
vitest run/vitest --run->rstest; plain Rstest already runs once and exits. Watch mode isrstest --watchorrstest watch. - Config imports:
defineConfigcomes from@rstest/core;defineWorkspaceis removed; use theprojectsfield. - Projects: use
defineInlineProject({ name, ... })only when thedependency-install-gate.mdcapability gate allows it; otherwise use plain named objects. UsedefineProjectfor top-level project config exports. - Config shape: remove Vitest's
testwrapper and move fields to the Rstest top level. Map exact fields through the official guide. - Coverage: add a capability-supported Rstest coverage package and use
coverage.reporters(plural). Replace@vitest/coverage-*only during cleanup after the Rstest scope is green. - Reporters: replace Vitest-only reporters; import third-party reporter classes instead of passing incompatible names.
- Setup: replace
@testing-library/jest-dom/vitestwith matcher registration viaexpect.extend(...)from@rstest/core. - Globals/APIs: imports from
vitest->@rstest/core;vi.<api>/vitest.<api>->rs.<api>. Avoid mixingviandrsin a migrated file. - Mocks:
rs.mock('./module')looks for__mocks__; use newer helpers/options such as{ mock: true }or{ spy: true }only when thedependency-install-gate.mdcapability gate allows them. Otherwise use explicit factories or manual mocks. - Async mock factories: Rstest does not support returning an async function when mocking a module value. Migrate Vitest patterns that await the actual module inside the factory to static
importActualimports plus a synchronous factory. - CJS mocking: use
rs.mockRequire()/rs.doMockRequire()forrequire()paths.
Build config
- Rstest uses Rsbuild/Rspack instead of Vite/Rollup. Translate Vite
definetosource.define, externalization tooutput.externals, and plugins to compatible adapters/Rsbuild plugins before rewriting tests.
Vitest-specific enforcement
1. Delete scope-local vitest.config.* and truly legacy vitest.setup.* only after the migrated scope is green. If a setup file was rewritten and is still referenced by Rstest setupFiles, rename or copy it to a Rstest-owned name such as rstest.setup.* before deleting the legacy Vitest-named file. Drop shared vitest.workspace.*, root shared config, and @vitest/* devDeps only after no scope still uses Vitest. 2. Do not re-record Vitest snapshots just to update headers. Vitest and Rstest snapshot files are byte-compatible below the header line; run -u only for expected body diffs. 3. Do not carry the Vite mental model into Rstest. Prefer adapters and Rsbuild/Rspack config translations over custom test rewrites.