关于 vitest
Vitest 是面向 Vite 项目的测试框架,适用于前端和 TypeScript 项目。它提供 Jest 风格 API、原生 ESM 支持、浏览器模式及并行测试。
主要功能
- 01Jest 风格测试 API
- 02原生 ESM 支持
- 03模拟函数与计时器
- 04浏览器模式测试
- 05监视模式与并行执行
- 06覆盖率与报告输出
适用场景
- 01测试 Vite 应用
- 02测试 TypeScript 代码
- 03在真实浏览器中测试组件
- 04迁移 Jest 测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ itechmeat/ llm-code --skill vitest安装后在 Claude Code 中输入/vitest确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api.mdbrowser.mdcli.mdconfig.mdexpect.mdmocking.md详细介绍
Vitest
由 Vite 驱动的下一代测试框架。
快速导航
- 测试 API - test、describe、钩子
- Expect API - 匹配器与断言
- 模拟 - vi.fn、vi.mock、伪造计时器
- 配置 - vitest.config.ts 选项
- CLI - 命令行参考
- 浏览器模式 - 真实浏览器测试
适用场景
- 测试基于 Vite 的应用(共享配置)
- 需要兼容 Jest 的 API 且原生支持 ESM
- 在真实浏览器中进行组件测试
- 支持 HMR 的快速监听模式
- 无需额外配置即可测试 TypeScript
- 并行执行测试
安装
安装:npm install -D vitest。在 v5 中需要 Node.js >=22 和 Vite >=6.4。
版本亮点(5.0.0)
- 要求: 需要 Node.js >=22 和 Vite >=6.4。
@vitest/runner已内联(该包不再发布),expect也已内联,因此旧的入口点已被移除。 - 模拟/计时器行为: 默认在每个测试前清除模拟,并且现在可以模拟
Temporal(无论是否使用伪造计时器)。 - 被替换的 API:
sequential测试/套件选项已被移除,改用concurrent;webdriverio浏览器 provider 已被移除;toHaveTextContent变为严格匹配,替代方案是toMatchTextContent;当函数未能及时 resolve 时,expect.poll会失败。 - 新的默认值/输出:
attachmentsDir默认为.vitest/attachments/(原为.vitest-attachments/),blob/json/junit/html reporter 的输出默认位于.vitest;引入了createReportAPI 和.vitest报告目录约定。 - 项目: 内联项目默认扩展根配置,支持嵌套项目,不同的项目共享一个 Vite 服务,且配置文件的查找不再从祖先目录开始(父目录不再适用)。
- 浏览器: locator 对象取代 locator 字符串,
locators.exact默认开启,新增screenshotDirectory配置控制toMatchScreenshot的输出。 - 其他: benchmark 公共 API 已重写,采用可插拔的 provider API;
-p是--project的简写;-t使用>作为分隔符;覆盖率thresholds.perFile接受对象,并支持 TypeScript 构建模式和vitest list静态解析。
版本亮点(4.1.0 -> 4.1.6)
- 新增控制流钩子:
aroundEach和aroundAll。 - 测试元数据扩展了标签、
meta,并改进了test.extend的类型推断。 - CLI 新增
--detect-async-leaks、更丰富的--update模式,以及vitest list的静态收集。 - 浏览器模式新增 Playwright 持久化上下文、
userEvent.wheel,以及更强的 trace/产物处理。 - 模拟/计时器新增可释放的
doMock()、mockThrow/mockThrowOnce以及setTickMode。 4.1.4新增实验性 ARIA 快照、JSON reporter 的filterMeta,并将assertion作为公开实验性字段暴露。4.1.5新增覆盖率instrumenter支持,并改进了 reporter/UI 在大型快照和 HTML 输出方面的行为。4.1.6收紧了浏览器截图路径解析,并修复了并发测试调度中sequence.concurrent的处理。
快速开始
// sum.js
export function sum(a, b) {
return a + b;
}
// sum.test.js
import { expect, test } from "vitest";
import { sum } from "./sum.js";
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe(3);
});
// package.json
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"coverage": "vitest run --coverage"
}
}
配置
// vitest.config.ts (recommended)
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true, // Enable global test APIs
environment: "jsdom", // Browser-like environment
include: ["**/*.{test,spec}.{js,ts,jsx,tsx}"],
coverage: {
provider: "v8",
reporter: ["text", "html"],
},
},
});
或者扩展 Vite 配置:
// vite.config.ts
/// <reference types="vitest/config" />
import { defineConfig } from "vite";
export default defineConfig({
test: {
// test options
},
});
测试文件命名
默认情况下,测试文件名中必须包含 .test. 或 .spec.:
sum.test.jssum.spec.ts__tests__/sum.js
常用命令
# Watch mode (default)
vitest
# Single run
vitest run
# With coverage
vitest run --coverage
# Filter by file/test name
vitest sum
vitest -t "should add"
# UI mode
vitest --ui
# Browser tests
vitest --browser.enabled
常见模式
基础测试
import { describe, it, expect, beforeEach } from "vitest";
describe("Calculator", () => {
let calc: Calculator;
beforeEach(() => {
calc = new Calculator();
});
it("adds numbers", () => {
expect(calc.add(1, 2)).toBe(3);
});
it("throws on invalid input", () => {
expect(() => calc.add("a", 1)).toThrow();
});
});
模拟
import { vi, expect, test } from "vitest";
import { fetchUser } from "./api";
vi.mock("./api", () => ({
fetchUser: vi.fn(),
}));
test("uses mocked API", async () => {
vi.mocked(fetchUser).mockResolvedValue({ name: "John" });
const user = await fetchUser(1);
expect(fetchUser).toHaveBeenCalledWith(1);
expect(user.name).toBe("John");
});
快照测试
import { expect, test } from "vitest";
test("matches snapshot", () => {
const result = generateConfig();
expect(result).toMatchSnapshot();
});
// Inline snapshot (auto-updates)
test("inline snapshot", () => {
expect({ foo: "bar" }).toMatchInlineSnapshot();
});
异步测试
import { expect, test } from "vitest";
test("async/await", async () => {
const result = await fetchData();
expect(result).toBeDefined();
});
test("resolves", async () => {
await expect(Promise.resolve("ok")).resolves.toBe("ok");
});
test("rejects", async () => {
await expect(Promise.reject(new Error())).rejects.toThrow();
});
伪造计时器
import { vi, expect, test, beforeEach, afterEach } from "vitest";
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
test("advances time", () => {
const callback = vi.fn();
setTimeout(callback, 1000);
vi.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
});
从 Jest 迁移
大多数 Jest 代码只需极少改动即可运行:
- import { jest } from '@jest/globals'
+ import { vi } from 'vitest'
- jest.fn()
+ vi.fn()
- jest.mock('./module')
+ vi.mock('./module')
- jest.useFakeTimers()
+ vi.useFakeTimers()
主要差异:
- 使用
vi代替jest - 默认不启用全局变量(需添加
globals: true) vi.mock会被提升(非提升请使用vi.doMock)- 没有
jest.requireActual(使用vi.importActual)
环境选择
// vitest.config.ts
{
test: {
environment: 'jsdom', // or 'happy-dom', 'node', 'edge-runtime'
}
}
// Per-file (docblock at top)
/** @vitest-environment jsdom */
TypeScript
// tsconfig.json
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
参考资料
有关以下内容的详细文档,请参阅 references/ 目录:
- 测试 API 与钩子
- 所有 expect 匹配器
- 模拟函数与模块
- 配置选项
- 命令行命令
- 浏览器模式测试
链接
评论
支持 Markdown