Migration guide

    Jest → Vitest, step by step.

    Vitest is close to a drop-in for Jest. Same describe/test/expect surface, but native ESM, 5–10× faster startup, and it runs on your Vite config. Most of the work is mechanical: swap the runner, turn jest.* into vi.*, then chase down a handful of behavioural differences that bite. Here's every step.

    Refactyl doesn't migrate Jest to Vitest yet. This guide covers the manual path; the waitlist notifies you when the verified engine ships.

    Why this migration is hard to get right

    Jest globals aren't globals in Vitest by default

    Jest injects describe, test, expect, vi globally without imports. Vitest requires explicit imports unless you set globals: true in vitest.config.ts, and even then the vi object (the Jest mock equivalent) needs importing. A naive runner swap surfaces hundreds of 'describe is not defined' errors.

    ESM vs CJS transform differences

    Jest runs on Node.js CommonJS via Babel or ts-jest, giving it a legacy transform path that handles dynamic require and module.exports. Vitest runs native ESM, so files that worked with jest.mock() hoisting may fail because ESM module evaluation order differs from CJS. Import order bugs that were hidden surface.

    Mock API subtle differences

    jest.fn(), jest.mock(), jest.spyOn() map to vi.fn(), vi.mock(), vi.spyOn(), but not identically. jest.mock() auto-mocking behaviour, mockReturnValue chaining, and module factory functions have edge cases where the Vitest equivalent behaves differently. Each needs testing.

    How to migrate manually

      1

      Install Vitest, remove Jest

      Install @vitest/ui @vitest/coverage-v8 (or istanbul), remove jest, babel-jest, @types/jest, jest-environment-jsdom. Add vitest to devDependencies.

      2

      Create vitest.config.ts

      Configure the test runner: environment (jsdom for React, node for server code), include pattern, coverage thresholds. If you had a jest.config.js, most options translate directly.

      3

      Update package.json scripts

      Replace "jest" → "vitest run" in your test script. "jest --watch" → "vitest". "jest --coverage" → "vitest run --coverage". If you use a CI flag like --ci, add --reporter=verbose.

      4

      Add globals: true OR add explicit imports

      Either set globals: true in vitest.config.ts (closest to Jest behaviour) or add `import { describe, test, expect, vi } from 'vitest'` to each test file. The latter is more explicit and avoids IDE type confusion.

      5

      Replace jest.* with vi.*

      Global search-and-replace: jest.fn() → vi.fn(), jest.mock() → vi.mock(), jest.spyOn() → vi.spyOn(), jest.useFakeTimers() → vi.useFakeTimers(), jest.clearAllMocks() → vi.clearAllMocks(), jest.resetModules() → vi.resetModules(). Most are 1:1.

      6

      Run vitest run and fix ESM issues

      Run the suite. The most common remaining failures are dynamic require() calls (convert to import()), __dirname/__filename references (replace with fileURLToPath(import.meta.url)), and jest.config.js options that don't exist in Vitest (remove moduleNameMapper if you've switched to Vite path aliases).

    What Refactyl's verified version will do

    Roadmap

    Refactyl doesn't run this migration yet. When it ships, the bar will be the same as every other Refactyl path: every file gated by a real vitest run run, repaired until clean, or clearly flagged with the reason. No unverified files ship.

    The public benchmark methodology is at refactyl.com/benchmark . The same dual-metric approach will apply here.

    Manual / DIY vs Refactyl (roadmap)

    This table describes what Refactyl's JestVitest engine will do. It isn't live yet.

    ConcernManual / DIYRefactyl (roadmap)
    Test startup timeJest cold-starts in 2–5s for moderate suitesVitest with native ESM and caching: sub-second on warm runs
    Global mock replacementManual regex + file-by-file jest.* → vi.* substitutionWill replace every jest.fn / mock / spy / timer call in batch, once live
    ESM compatibility fixesrequire() and __dirname errors surface one-by-one at runtimeWill be detected and converted in the same pass as the runner migration
    vitest.config.ts generationWritten by hand from the Vitest docsWill be generated from your existing jest.config.js, preserving test patterns and thresholds
    Verification gateYou find out it worked when CI passesA passing vitest run will be required before delivery

    FAQ

    Jest → Vitest migration: common questions

    Real questions engineers ask before migrating Jest to Vitest, answered honestly.

    On the roadmap

    Want Refactyl to do this for you?

    Join the waitlist and we'll notify you when the JestVitest engine ships. The bar is the same as every other Refactyl path: every file gated by a real vitest run run before handoff.

    Join the waitlist →

    Refactyl doesn't migrate Jest to Vitest yet. No misleading trial, no fake demo.