用途
Vitest 是一个由 Vite 驱动的下一代测试框架,专为现代 TypeScript/JavaScript 项目设计。它通过基于 HMR 的测试运行提供高速的测试执行,原生支持 ESM,并具备 TypeScript 优先的设计。它提供与 Jest 兼容的 API,便于已有测试迁移。
主要能力
- Vite 原生:基于 HMR 的即时测试执行(资料称比 Jest 快 10-100 倍)。
- TypeScript 优先:内置 TypeScript 支持,无需额外配置。
- ESM 原生:原生 ES 模块、async/await、顶层 await。
- Jest 兼容:提供兼容 API,便于迁移。
- 快照测试:内置快照支持。
- 组件测试:可集成 React Testing Library、Vue Test Utils。
- 覆盖率:内置 v8/c8 覆盖率(资料称比 Istanbul 更快)。
- UI 模式:用于测试调试的 Web UI。
使用方式
安装:
npm install -D vitest
# TypeScript types (usually auto-detected)
npm install -D @vitest/ui # Optional: UI mode
配置 Vitest(vitest.config.ts):
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true, // Use describe/it/expect globally
environment: 'node', // or 'jsdom' for DOM testing
coverage: {
provider: 'v8', // or 'istanbul'
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'dist/',
'**/*.test.ts',
'**/*.spec.ts',
],
},
include: ['**/*.{test,spec}.{ts,tsx}'],
exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'],
},
});
TypeScript 配置(tsconfig.json):
{
"compilerOptions": {
"types": ["vitest/globals"] // For global describe/it/expect
}
}
不使用全局变量时可改为 import { describe, it, expect } from 'vitest';。
package.json 脚本:
{
"scripts": {
"test": "vitest run", // CI mode (single run)
"test:watch": "vitest", // Watch mode (default)
"test:ui": "vitest --ui", // UI mode
"test:coverage": "vitest run --coverage"
}
}
核心测试结构使用 describe/it/expect,并支持 beforeEach、afterEach 等钩子:
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
describe('Calculator', () => {
let calculator: Calculator;
beforeEach(() => {
calculator = new Calculator();
});
it('adds two numbers correctly', () => {
const result = calculator.add(2, 3);
expect(result).toBe(5);
});
it('handles negative numbers', () => {
expect(calculator.add(-5, 3)).toBe(-2);
});
});
类型测试可使用 expectTypeOf 与 assertType:
import { describe, it, expectTypeOf, assertType } from 'vitest';
interface User {
id: number;
name: string;
email: string;
}
describe('Type Safety', () => {
it('ensures correct types', () => {
const user: User = {
id: 1,
name: 'Alice',
email: 'alice@example.com',
};
expectTypeOf(user.id).toBeNumber();
expectTypeOf(user.name).toBeString();
expectTypeOf(user).toMatchTypeOf<User>();
assertType<User>(user);
});
});
Mock 与 Spy 支持 vi.mock、vi.spyOn、vi.fn,并可自定义实现与一次性实现:
import { describe, it, expect, vi } from 'vitest';
vi.mock('./api', () => ({
fetchUser: vi.fn(),
}));
const mockFn = vi.fn((x: number) => x * 2);
mockFn.mockImplementation((x: number) => x + 10);
mockFn.mockImplementationOnce((x: number) => 100);
定时器模拟可使用 vi.useFakeTimers、vi.advanceTimersByTime、vi.runAllTimersAsync。
React 集成安装:
npm install -D @testing-library/react @testing-library/jest-dom @testing-library/user-event
npm install -D jsdom # For DOM environment
React 配置示例:
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
},
});
setup 文件:
import '@testing-library/jest-dom';
import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import * as matchers from '@testing-library/jest-dom/matchers';
expect.extend(matchers);
afterEach(() => {
cleanup();
});
React 组件测试与 Hook 测试分别使用 render/screen/userEvent 与 renderHook/act。
Vue 集成安装:
npm install -D @vue/test-utils @vitejs/plugin-vue
npm install -D happy-dom # Faster alternative to jsdom
Vue 配置示例:
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
test: {
globals: true,
environment: 'happy-dom',
setupFiles: './src/test/setup.ts',
},
});
Vue 组件测试使用 mount 与 wrapper.find、wrapper.text、wrapper.emitted 等。
异步测试支持 async/await,并可使用 rejects、resolves 等匹配器。快照测试支持 toMatchSnapshot 与 toMatchInlineSnapshot,并可通过 expect.addSnapshotSerializer 自定义序列化。
覆盖率配置示例:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html', 'lcov'],
reportsDirectory: './coverage',
exclude: [
'node_modules/',
'dist/',
'**/*.test.ts',
'**/*.spec.ts',
'**/*.config.ts',
'**/types/',
],
thresholds: {
lines: 80,
functions: 80,
branches: 75,
statements: 80,
},
all: true, // Include untested files in coverage report
},
},
});
运行覆盖率:
npx vitest run --coverage
npx vitest --coverage --ui
npx vitest run --coverage --coverage.lines=90
从 Jest 迁移时,Vitest 提供 Jest 兼容 API,但新代码建议使用 vi 代替 jest。迁移步骤包括卸载旧依赖并安装 Vitest、更新 package.json 脚本、用 vitest.config.ts 替换 jest.config.js、并更新测试文件中的导入与 mock 调用。
高级模式包括 describe.concurrent 并行测试、Test Context 上下文注入、以及 expect.extend 自定义匹配器。
适用场景
Vitest 适用于现代 TypeScript/JavaScript 项目的单元测试与组件测试,尤其是已使用 Vite 的项目;也可用于需要 ESM、TypeScript 类型测试、快照测试、覆盖率统计和可视化 UI 调试的场景;对从 Jest 迁移的团队也可作为替代方案。可用于 React 与 Vue 的组件与 Hook 测试。
限制与注意事项
资料未提供价格、授权协议、支持的运行环境版本或性能数据的第三方验证。CI/CD 中应使用 vitest run 而非默认的 watch 模式(后者会导致 CI 挂起)。最佳实践建议包括:使用 globals: true、优先使用 vi 而非 jest、使用 v8 覆盖率、保持测试独立隔离、mock 外部依赖、使用 TypeScript、在 CI 中使用单次运行模式、利用 UI 模式调试、使用 describe.concurrent 并行独立测试、保持测试聚焦。