vitest
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVitest - Modern Test Framework
Vitest - 现代化测试框架
Status: Production Ready
Last Updated: 2026-02-06
Vitest Version: 4.x
Vite Compatibility: 6.x
状态:生产可用
最后更新:2026-02-06
Vitest版本:4.x
Vite兼容性:6.x
Quick Start
快速开始
bash
undefinedbash
undefinedInstall
安装
pnpm add -D vitest
pnpm add -D vitest
Add to package.json
添加至package.json
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage"
}
}
---{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage"
}
}
---Configuration
配置
Minimal Config (vitest.config.ts)
最简配置(vitest.config.ts)
typescript
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
},
});typescript
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
},
});React Config
React配置
typescript
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'],
css: true,
},
});typescript
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'],
css: true,
},
});Cloudflare Workers Config
Cloudflare Workers配置
typescript
import { defineConfig } from 'vitest/config';
import { cloudflare } from '@cloudflare/vite-plugin';
export default defineConfig({
plugins: [cloudflare()],
test: {
globals: true,
environment: 'node',
// Workers tests often need longer timeouts for D1/KV
testTimeout: 10000,
},
});typescript
import { defineConfig } from 'vitest/config';
import { cloudflare } from '@cloudflare/vite-plugin';
export default defineConfig({
plugins: [cloudflare()],
test: {
globals: true,
environment: 'node',
// Workers测试通常需要为D1/KV设置更长的超时时间
testTimeout: 10000,
},
});Mocking Patterns
Mock模式
vi.mock - Module Mocking
vi.mock - 模块Mock
typescript
import { vi, describe, it, expect } from 'vitest';
import { fetchUser } from './api';
// Mock entire module
vi.mock('./api', () => ({
fetchUser: vi.fn(),
}));
describe('User component', () => {
it('fetches user data', async () => {
// Type-safe mock implementation
vi.mocked(fetchUser).mockResolvedValue({ id: 1, name: 'Test' });
// ... test code
expect(fetchUser).toHaveBeenCalledWith(1);
});
});typescript
import { vi, describe, it, expect } from 'vitest';
import { fetchUser } from './api';
// Mock整个模块
vi.mock('./api', () => ({
fetchUser: vi.fn(),
}));
describe('User组件', () => {
it('获取用户数据', async () => {
// 类型安全的Mock实现
vi.mocked(fetchUser).mockResolvedValue({ id: 1, name: 'Test' });
// ... 测试代码
expect(fetchUser).toHaveBeenCalledWith(1);
});
});vi.spyOn - Spy on Methods
vi.spyOn - 方法监听
typescript
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
describe('Date handling', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01'));
});
afterEach(() => {
vi.useRealTimers();
});
it('uses mocked date', () => {
expect(new Date().getFullYear()).toBe(2026);
});
});typescript
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
describe('日期处理', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01'));
});
afterEach(() => {
vi.useRealTimers();
});
it('使用模拟日期', () => {
expect(new Date().getFullYear()).toBe(2026);
});
});vi.stubGlobal - Global Mocks
vi.stubGlobal - 全局Mock
typescript
import { vi, describe, it, expect } from 'vitest';
describe('Environment', () => {
it('mocks fetch globally', async () => {
const mockFetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'test' }),
});
vi.stubGlobal('fetch', mockFetch);
const response = await fetch('/api/test');
expect(mockFetch).toHaveBeenCalledWith('/api/test');
vi.unstubAllGlobals();
});
});typescript
import { vi, describe, it, expect } from 'vitest';
describe('环境变量', () => {
it('全局Mock fetch', async () => {
const mockFetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'test' }),
});
vi.stubGlobal('fetch', mockFetch);
const response = await fetch('/api/test');
expect(mockFetch).toHaveBeenCalledWith('/api/test');
vi.unstubAllGlobals();
});
});Snapshot Testing
快照测试
Basic Snapshots
基础快照
typescript
import { describe, it, expect } from 'vitest';
describe('Component output', () => {
it('matches snapshot', () => {
const result = renderComponent({ title: 'Hello' });
expect(result).toMatchSnapshot();
});
it('matches inline snapshot', () => {
const result = { name: 'test', count: 42 };
expect(result).toMatchInlineSnapshot(`
{
"count": 42,
"name": "test",
}
`);
});
});typescript
import { describe, it, expect } from 'vitest';
describe('组件输出', () => {
it('匹配快照', () => {
const result = renderComponent({ title: 'Hello' });
expect(result).toMatchSnapshot();
});
it('匹配内联快照', () => {
const result = { name: 'test', count: 42 };
expect(result).toMatchInlineSnapshot(`
{
"count": 42,
"name": "test",
}
`);
});
});Update Snapshots
更新快照
bash
undefinedbash
undefinedUpdate all snapshots
更新所有快照
vitest run --update
vitest run --update
Interactive update
交互式更新
vitest --ui
---vitest --ui
---In-Source Testing
源码内测试
Test code directly in source files (tree-shaken in production):
typescript
// src/utils/math.ts
export function add(a: number, b: number): number {
return a + b;
}
// In-source test block
if (import.meta.vitest) {
const { describe, it, expect } = import.meta.vitest;
describe('add', () => {
it('adds two numbers', () => {
expect(add(1, 2)).toBe(3);
});
});
}Config for in-source testing:
typescript
// vitest.config.ts
export default defineConfig({
test: {
includeSource: ['src/**/*.{js,ts}'],
},
define: {
'import.meta.vitest': 'undefined', // Tree-shake in production
},
});直接在源码文件中编写测试代码(生产环境下会被摇树优化移除):
typescript
// src/utils/math.ts
export function add(a: number, b: number): number {
return a + b;
}
// 源码内测试块
if (import.meta.vitest) {
const { describe, it, expect } = import.meta.vitest;
describe('add', () => {
it('两数相加', () => {
expect(add(1, 2)).toBe(3);
});
});
}源码内测试配置:
typescript
// vitest.config.ts
export default defineConfig({
test: {
includeSource: ['src/**/*.{js,ts}'],
},
define: {
'import.meta.vitest': 'undefined', // 生产环境下摇树移除
},
});Workspace Configuration (Monorepos)
工作区配置(单体仓库)
typescript
// vitest.workspace.ts
import { defineWorkspace } from 'vitest/config';
export default defineWorkspace([
// Each package can have its own config
'packages/*/vitest.config.ts',
// Or define inline
{
test: {
name: 'unit',
include: ['src/**/*.test.ts'],
environment: 'node',
},
},
{
test: {
name: 'browser',
include: ['src/**/*.browser.test.ts'],
browser: {
enabled: true,
provider: 'playwright',
name: 'chromium',
},
},
},
]);typescript
// vitest.workspace.ts
import { defineWorkspace } from 'vitest/config';
export default defineWorkspace([
// 每个包可拥有独立配置
'packages/*/vitest.config.ts',
// 或内联定义
{
test: {
name: 'unit',
include: ['src/**/*.test.ts'],
environment: 'node',
},
},
{
test: {
name: 'browser',
include: ['src/**/*.browser.test.ts'],
browser: {
enabled: true,
provider: 'playwright',
name: 'chromium',
},
},
},
]);Browser Mode Testing
浏览器模式测试
typescript
// vitest.config.ts
export default defineConfig({
test: {
browser: {
enabled: true,
provider: 'playwright', // or 'webdriverio'
name: 'chromium',
headless: true,
},
},
});bash
undefinedtypescript
// vitest.config.ts
export default defineConfig({
test: {
browser: {
enabled: true,
provider: 'playwright', // 或 'webdriverio'
name: 'chromium',
headless: true,
},
},
});bash
undefinedInstall browser provider
安装浏览器提供者
pnpm add -D @vitest/browser playwright
---pnpm add -D @vitest/browser playwright
---Coverage
覆盖率
bash
undefinedbash
undefinedInstall coverage provider
安装覆盖率提供者
pnpm add -D @vitest/coverage-v8
pnpm add -D @vitest/coverage-v8
Run with coverage
带覆盖率运行测试
vitest run --coverage
```typescript
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
exclude: [
'node_modules/',
'src/test/',
'**/*.d.ts',
],
thresholds: {
statements: 80,
branches: 80,
functions: 80,
lines: 80,
},
},
},
});vitest run --coverage
```typescript
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
exclude: [
'node_modules/',
'src/test/',
'**/*.d.ts',
],
thresholds: {
statements: 80,
branches: 80,
functions: 80,
lines: 80,
},
},
},
});Jest Migration
Jest迁移
Key Differences
核心差异
| Jest | Vitest |
|---|---|
| |
| |
| |
| |
| |
| |
| Jest | Vitest |
|---|---|
| |
| |
| |
| |
| |
| |
Migration Steps
迁移步骤
- Replace imports:
typescript
// Before (Jest)
import { jest } from '@jest/globals';
// After (Vitest)
import { vi } from 'vitest';- Update config:
typescript
// jest.config.js → vitest.config.ts
export default defineConfig({
test: {
globals: true, // Enables describe/it/expect without imports
environment: 'jsdom',
},
});- Replace jest. with vi.:
bash
undefined- 替换导入:
typescript
// 之前(Jest)
import { jest } from '@jest/globals';
// 之后(Vitest)
import { vi } from 'vitest';- 更新配置:
typescript
// jest.config.js → vitest.config.ts
export default defineConfig({
test: {
globals: true, // 无需导入即可使用describe/it/expect
environment: 'jsdom',
},
});- 替换jest.为vi.:
bash
undefinedQuick replace (review changes carefully)
快速替换(请仔细检查变更)
find src -name "*.test.ts" -exec sed -i 's/jest./vi./g' {} ;
---find src -name "*.test.ts" -exec sed -i 's/jest./vi./g' {} ;
---Common Patterns
常见模式
Testing Async Code
异步代码测试
typescript
import { describe, it, expect } from 'vitest';
describe('async operations', () => {
it('resolves promise', async () => {
const result = await fetchData();
expect(result).toBeDefined();
});
it('rejects with error', async () => {
await expect(failingOperation()).rejects.toThrow('Expected error');
});
});typescript
import { describe, it, expect } from 'vitest';
describe('异步操作', () => {
it('解析Promise', async () => {
const result = await fetchData();
expect(result).toBeDefined();
});
it('抛出指定错误', async () => {
await expect(failingOperation()).rejects.toThrow('预期错误');
});
});Testing with Fixtures
测试夹具使用
typescript
import { describe, it, expect, beforeEach } from 'vitest';
describe('with fixtures', () => {
let testData: TestData;
beforeEach(() => {
testData = createTestFixture();
});
it('uses fixture', () => {
expect(testData.id).toBeDefined();
});
});typescript
import { describe, it, expect, beforeEach } from 'vitest';
describe('使用夹具', () => {
let testData: TestData;
beforeEach(() => {
testData = createTestFixture();
});
it('使用夹具数据', () => {
expect(testData.id).toBeDefined();
});
});Parameterized Tests
参数化测试
typescript
import { describe, it, expect } from 'vitest';
describe.each([
{ input: 1, expected: 2 },
{ input: 2, expected: 4 },
{ input: 3, expected: 6 },
])('double($input)', ({ input, expected }) => {
it(`returns ${expected}`, () => {
expect(double(input)).toBe(expected);
});
});typescript
import { describe, it, expect } from 'vitest';
describe.each([
{ input: 1, expected: 2 },
{ input: 2, expected: 4 },
{ input: 3, expected: 6 },
])('翻倍($input)', ({ input, expected }) => {
it(`返回${expected}`, () => {
expect(double(input)).toBe(expected);
});
});Debugging
调试
Run Single Test
运行单个测试
bash
vitest run -t "test name"
vitest run src/specific.test.tsbash
vitest run -t "测试名称"
vitest run src/specific.test.tsDebug Mode
调试模式
bash
undefinedbash
undefinedWith Node inspector
使用Node调试器
node --inspect-brk ./node_modules/vitest/vitest.mjs run
node --inspect-brk ./node_modules/vitest/vitest.mjs run
Or use Vitest UI
或使用Vitest UI
vitest --ui
undefinedvitest --ui
undefinedWatch Mode
监听模式
bash
vitest # Watch mode (default)
vitest run # Single run
vitest watch # Explicit watchbash
vitest # 默认监听模式
vitest run # 单次运行
vitest watch # 显式开启监听Troubleshooting
问题排查
"Cannot find module" in mocks
Mock中出现“无法找到模块”
typescript
// Ensure mock path matches import path exactly
vi.mock('./api'); // Matches: import { x } from './api'
vi.mock('../api'); // Different! Won't work for './api' importstypescript
// 确保Mock路径与导入路径完全匹配
vi.mock('./api'); // 匹配:import { x } from './api'
vi.mock('../api'); // 不同!无法匹配'./api'的导入ESM/CJS Issues
ESM/CJS兼容问题
typescript
// vitest.config.ts - for CJS dependencies
export default defineConfig({
test: {
deps: {
inline: ['problematic-cjs-package'],
},
},
});typescript
// vitest.config.ts - 针对CJS依赖
export default defineConfig({
test: {
deps: {
inline: ['problematic-cjs-package'],
},
},
});Globals Not Defined
全局变量未定义
typescript
// If using globals: true but TypeScript complains
// Add to tsconfig.json:
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}typescript
// 若启用globals: true但TypeScript报错
// 添加至tsconfig.json:
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}See Also
相关链接
- skill - General testing patterns
testing-patterns - skill - React Testing Library integration
testing-library - Official docs: https://vitest.dev
- 技能 - 通用测试模式
testing-patterns - 技能 - React Testing Library集成
testing-library - 官方文档:https://vitest.dev