Skip to content

从 Jest 迁移

基于 Vitest v4.1.x 编写

速查

  • 命名空间整体替换:jest.*vi.*
  • factory 必须返回对象:vi.mock(p, () => ({ default: x }))
  • jest.requireActual()await vi.importActual()异步
  • 想保留全局 test / expectglobals: true + tsconfig "types": ["vitest/globals"]
  • done 回调不支持 → 改 async / await
  • __mocks__ 不自动加载 → 必须显式 vi.mock()
  • 环境变量:JEST_WORKER_IDVITEST_POOL_ID
  • ESM 无需 unstable_mockModule,直接 vi.mock

为什么能低成本迁移

Vitest 的 API 刻意对齐 Jest:describe / test / expect 的 matchers、test.each、快照、mock 系统几乎同名。多数测试文件只需把 jest. 改成 vi.,再调一处配置即可跑通。

API 映射

JestVitest注意
jest.fn()vi.fn()
jest.spyOn()vi.spyOn()
jest.mock()vi.mock()factory 返回格式有差异
jest.requireActual()await vi.importActual()异步,必须 await
jest.clearAllMocks()vi.clearAllMocks()
jest.resetAllMocks()vi.resetAllMocks()
jest.restoreAllMocks()vi.restoreAllMocks()
jest.useFakeTimers()vi.useFakeTimers()
jest.setTimeout(n)vi.setConfig({ testTimeout: n })
jest.replaceProperty()vi.stubEnv() / vi.spyOn()
JEST_WORKER_IDVITEST_POOL_ID环境变量名不同

factory 返回格式(最易踩)

ts
// ❌ Jest 可以直接返回值
jest.mock("./path", () => "hello");

// ✅ Vitest 必须返回模块对象,默认导出写 default
vi.mock("./path", () => ({ default: "hello" }));

vi.mock("./userService", () => ({
  default: vi.fn(),
  getUser: vi.fn(),
}));

全局 API

Jest 默认注入全局 test / expect;Vitest 默认要 import。要保留 Jest 习惯:

ts
// vitest.config.ts
export default defineConfig({ test: { globals: true } });
json
// tsconfig.json
{ "compilerOptions": { "types": ["vitest/globals"] } }

done 回调不支持

ts
// ❌ Jest 的 done 风格
test("old", (done) => {
  asyncOp((res) => {
    expect(res).toBeDefined();
    done();
  });
});

// ✅ 改为 async / await
test("new", async () => {
  const res = await new Promise((resolve) => asyncOp(resolve));
  expect(res).toBeDefined();
});

importActual 是异步的

ts
// Jest
const actual = jest.requireActual("./utils");

// Vitest —— 必须 await
const actual = await vi.importActual<typeof import("./utils")>("./utils");

mocks 目录差异

  • Jest__mocks__/axios.js 会被自动使用。
  • Vitest:必须显式 vi.mock("axios"),才会去找 __mocks__/axios.ts

ESM 场景

Jest 处理 ESM 要用 jest.unstable_mockModule + 动态 import;Vitest 原生 ESM,直接 vi.mock() 即可,无特殊 API。

迁移步骤建议

  1. 安装:pnpm add -D vitest,按需加 jsdom / happy-dom@vitest/coverage-v8
  2. 新建 vitest.config.ts(或 mergeConfigvite.config.ts),需要时设 globals: true
  3. 全局替换 jest.vi.,把 requireActual 改成 await vi.importActual
  4. 处理 vi.mock factory 返回对象格式、done 回调。
  5. package.json 脚本 jestvitest run,CI 跑通后删除 jest / babel-jest / ts-jest 依赖与配置。

vi.mock 的提升语义见 模拟(Mock);配置项见 配置