Vitest vs Jest:2026 看 JS 测试框架

起因

JS 项目测试框架历史:

  • mocha + chai + sinon(老)
  • jest(Facebook,2014+,事实标准)
  • vitest(Vite 团队,2021+,Vite-native)

新项目选谁?老 jest 项目要不要迁?下面经验。

jest

// my.test.js
const { add } = require('./math');

describe('math', () => {
    test('add', () => {
        expect(add(1, 2)).toBe(3);
    });
});
npx jest

10 年生态,全 JS 圈子默认。

优势

  • 教程 / 答案最多
  • 巨大插件生态(jest-dom / jest-axe / ...)
  • snapshot testing 成熟
  • mock 系统强(auto-mock / manual mock)

劣势

  • 启动慢(2-5 秒只为跑 1 个测试)
  • ESM 支持差(CJS 优先,ESM 配置复杂)
  • TS 要 ts-jest / @swc/jest 等
  • 慢(百 test 几十秒)

vitest

// my.test.js
import { test, expect, describe } from 'vitest';
import { add } from './math';

describe('math', () => {
    test('add', () => {
        expect(add(1, 2)).toBe(3);
    });
});
npx vitest

API jest-compat(expect / describe 大部分一致)。
基于 Vite,原生 ESM + esbuild + TS 直接。

优势

  • 极快:watch mode HMR-like,改文件即重跑相关 test
  • ESM 原生 + TS 原生
  • Vite 项目同 config 共享
  • jest API 兼容(容易迁移)
  • 内置 coverage / UI / browser mode

劣势

  • 生态比 jest 小(但每年增长快)
  • 某些 jest 插件没等价
  • snapshot 跟 jest 略不同(导致迁移微调)

性能对比

中型项目 500 test:

jest vitest
cold start 8s 1.5s
全跑 25s 6s
watch(改 1 file) 5s 0.3s
coverage 35s 10s

vitest 普遍 3-5x 快。开发循环 watch mode 差距更大。

写法对比

写法 99% 一致:

// 通用
describe('x', () => {
    beforeEach(() => { ... });
    test('does y', async () => {
        expect(...).toBe(...);
    });
});

vitest 加:

import { vi } from 'vitest';      // jest 是全局 vi → jest.fn / mock

jest.fn()vi.fn()jest.spyOnvi.spyOnjest.mockvi.mock

config 注入全局可让 jest 写法直接跑:

// vitest.config.ts
export default defineConfig({
    test: { globals: true },     // 启用 describe / test / expect 全局
});

mock

// vitest
import { vi } from 'vitest';

vi.mock('./api', () => ({
    fetchUser: vi.fn(() => Promise.resolve({ name: 'mock' })),
}));

const spy = vi.spyOn(console, 'log');

跟 jest 几乎一样。

snapshot

expect(rendered).toMatchSnapshot();

生成 __snapshots__/my.test.js.snap
vitest 用 jest 相同格式。

inline snapshot:

expect(rendered).toMatchInlineSnapshot(`"<div>hello</div>"`);

review 时 inline 直观。

React Testing Library 集成

// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [react()],
    test: {
        environment: 'jsdom',
        setupFiles: './test/setup.ts',
    },
});
// test/setup.ts
import '@testing-library/jest-dom/vitest';     // matchers
import { render, screen } from '@testing-library/react';
import { test, expect } from 'vitest';
import App from './App';

test('renders title', () => {
    render(<App />);
    expect(screen.getByText('Hello')).toBeInTheDocument();
});

跟 jest 配 RTL 几乎一样。

browser mode(vitest 1.0+)

test: {
    browser: { enabled: true, name: 'chromium' },
}

测试在真实浏览器跑(替代 jsdom)。
适合:测 component 在真实环境(layout / CSS / fetch)。

jest 不能直接跑浏览器(要 jest-playwright 等组合)。

迁移 jest → vitest

npm install -D vitest @vitest/ui

package.json:

"scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage"
}

代码层 99% 测试直接跑:

// 全局 import 替代
- import { describe, test, expect } from '@jest/globals';
+ // (with globals: true 不需要)
+ import { describe, test, expect } from 'vitest';

- jest.fn()
+ vi.fn()

- jest.mock('./api')
+ vi.mock('./api')

一般 sed 批量替换 + 个别手动调。
中型项目几小时迁移完。

CI 集成

- run: pnpm test --coverage
- uses: codecov/codecov-action@v4

不变。GitHub Actions / GitLab / CircleCI 都 vitest 友好。

真实迁移 case

我们一个 React 项目,jest + RTL + 200 test:

  • ci 时间从 90s → 25s
  • watch mode 改文件秒返馈
  • ts-jest 配置删了(vite 自带 TS)
  • 配置文件简化

但迁完一周才完全稳:

  • 几个 mock 行为微差
  • snapshot whitespace 略不同需 regenerate
  • 某些 jest plugin(如 jest-axe)没 vitest 版本(找替代)

何时不必迁

  • 老项目大 jest,团队稳定 → 不动
  • 用极偏 jest 插件 → 维持

决策

  • 新项目 → vitest(无脑选)
  • 大老项目 + 团队稳 → jest,可不迁
  • 小老项目 → 半天迁

与 node:test 对比

Node 20+ 内置 node --test

import { test } from 'node:test';
import assert from 'node:assert';

test('add', () => {
    assert.strictEqual(add(1, 2), 3);
});

无依赖。简单 unit test 够。
但 mock / snapshot / coverage 弱于 jest / vitest,复杂项目仍 vitest。

踩过的坑

  1. vi.mock 提升:vite 把 mock 提升到 file 顶部 → 跟 import 顺序
    交互奇怪。简单场景 OK,复杂用 mock factory + lazy。

  2. globals: true 没设:jest 写法报 describe is not defined

  3. CSS import 报错:vitest 不像 jest 自动 mock CSS。配
    vitest.config.tscss: truecss.modules.classNameStrategy

  4. timeout 默认 5s:复杂 e2e 测试超时。testTimeout: 30000

  5. watch 没 trigger:file change 但 test 没重跑 → vitest cache
    bug。vitest --no-cache 或 restart。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。