mcpField
V
vitest

vitest

github.com/itechmeat测试与质量24199 次安装1 周前更新
代码仓库

关于 vitest

Vitest 是面向 Vite 项目的测试框架,适用于前端和 TypeScript 项目。它提供 Jest 风格 API、原生 ESM 支持、浏览器模式及并行测试。

主要功能

  1. 01Jest 风格测试 API
  2. 02原生 ESM 支持
  3. 03模拟函数与计时器
  4. 04浏览器模式测试
  5. 05监视模式与并行执行
  6. 06覆盖率与报告输出

适用场景

  1. 01测试 Vite 应用
  2. 02测试 TypeScript 代码
  3. 03在真实浏览器中测试组件
  4. 04迁移 Jest 测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/itechmeat/llm-code --skill vitest

安装后在 Claude Code 中输入/vitest确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api.md
browser.md
cli.md
config.md
expect.md
mocking.md

详细介绍

Vitest

由 Vite 驱动的下一代测试框架。

快速导航

适用场景

  • 测试基于 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;引入了 createReport API 和 .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.js
  • sum.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