mcpField
V
vitest-testing

vitest-testing

github.com/laurigates测试与质量5988 次安装今天更新
代码仓库

关于 vitest-testing

vitest-testing 是指导 Vite 项目测试的技能,面向编写或配置 TypeScript 和 JavaScript 单元及集成测试的开发者。内容涵盖 Vitest 配置、覆盖率、模拟,以及识别 jsdom 测试中的无效断言。

主要功能

  1. 01配置 Vitest 与 Vite
  2. 02编写 TypeScript 和 JavaScript 测试
  3. 03模拟、间谍与快照测试
  4. 04运行覆盖率与基准测试
  5. 05识别 jsdom 断言陷阱

适用场景

  1. 01为 Vite 项目配置测试运行器
  2. 02从 Jest 迁移测试
  3. 03编写单元或集成测试
  4. 04检查覆盖率并避免无效 DOM 断言

安装

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

$npx skills add https://github.com/laurigates/claude-plugins --skill vitest-testing

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

附带文件REFERENCE.md

详细介绍

Vitest 测试

Vitest 是一款为 Vite 项目设计的现代测试运行器。它速度快、原生支持 ESM,并提供与 Jest 兼容的 API,同时具备更好的 TypeScript 支持和由 HMR 驱动的即时监听模式。

何时使用此技能

在以下情况下使用此技能……在以下情况下改用其他技能……
设置或配置 Vitest编写 E2E 浏览器测试(使用 playwright-testing)
编写 TS/JS 单元测试或集成测试测试 Python 代码(使用 python-testing)
从 Jest 迁移到 Vitest分析测试质量(使用 test-quality-analysis)
配置覆盖率阈值生成基于属性的测试(使用 property-based-testing)
使用模拟、间谍或假计时器验证测试有效性(使用 mutation-testing)

核心专长

  • 原生支持 Vite:复用 Vite 配置、转换和插件
  • 速度快:通过 HMR 驱动的监听模式即时反馈
  • 兼容 Jest:可直接替换,API 相似
  • TypeScript:一流的 TypeScript 支持
  • ESM:原生支持 ESM,无需转译
  • jsdom DOM 测试:以及其中会悄悄撒谎的断言(见下文)

安装

bun add --dev vitest
bun add --dev @vitest/coverage-v8      # Coverage (recommended)
bun add --dev happy-dom                # DOM testing (optional)
bunx vitest --version                  # Verify

配置(vitest.config.ts)

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
  },
});

常用命令

bunx vitest                            # Watch mode (default)
bunx vitest run                        # Run once (CI mode)
bunx vitest --coverage                 # With coverage
bunx vitest src/utils.test.ts          # Specific file
bunx vitest -t "should add numbers"    # Filter by name
bunx vitest related src/utils.ts       # Related tests
bunx vitest -u                         # Update snapshots
bunx vitest bench                      # Benchmarks
bunx vitest --ui                       # UI mode

编写测试

基本测试结构
import { describe, it, expect } from 'vitest';
import { add, multiply } from './math';

describe('math utils', () => {
  it('should add two numbers', () => {
    expect(add(2, 3)).toBe(5);
  });

  it('should multiply two numbers', () => {
    expect(multiply(2, 3)).toBe(6);
  });
});
常用断言
断言说明
toBe(value)严格相等
toEqual(value)深度相等
toStrictEqual(value)深度严格相等
toBeTruthy() / toBeFalsy()真值判断
toBeNull() / toBeUndefined()Null 检查
toBeGreaterThan(n) / toBeLessThan(n)数值比较
toBeCloseTo(n)浮点数比较
toMatch(regex) / toContain(str)字符串匹配
toHaveLength(n)数组/字符串长度
toHaveProperty(key)对象属性
toMatchObject(obj)对象部分匹配
toThrow(msg)是否抛出错误
异步测试
test('async test', async () => {
  const data = await fetchData();
  expect(data).toBe('expected');
});

test('promise resolves', async () => {
  await expect(fetchData()).resolves.toBe('expected');
});

test('promise rejects', async () => {
  await expect(fetchBadData()).rejects.toThrow('error');
});

jsdom 下的 DOM 测试——会撒谎的断言

environment: 'jsdom' 会为你提供一个没有布局引擎的 DOM,其 CSS 解析器也比浏览器的更有限。因此,一些看似自然的断言实际上是空洞的:它们会针对本来要捕捉的错误通过,形成了测试覆盖率,让人不再回头检查。

陷阱为什么它会针对错误通过应改为断言
对样式表设置的样式使用 el.style.overflowY内联样式为空;声明位于类规则中getComputedStyle(el).overflowY——jsdom 确实会解析注入的 <style> 规则
对 min() / calc() 值使用 getComputedStyle(el).widthjsdom 的解析器会悄悄丢弃整个声明,无论如何都会报告 ""/0样式表的源文本,或交由真实浏览器处理
任何有关尺寸或位置的断言getBoundingClientRect() 的值全为零;这里没有布局真实浏览器测试层
点击后立即断言异步渲染的内容面板仍为空,因此“未找到不良元素”自然成立刷新(await new Promise(r => setTimeout(r, 0))),然后在真正检查前断言容器非空

另外:jsdom 中不存在 Element.prototype.scrollIntoView,因此任何在挂载时将元素居中的代码路径都会抛出错误。请为它添加桩(Element.prototype.scrollIntoView = () => {})——这是测试框架的缺口,不是行为变更。

并且绝不要编写条件断言:

// Passes silently in exactly the case it was meant to catch — a renamed class.
if (found.length === 1) expect(found[0].textContent).toMatch(/x/);

// Assert unconditionally.
expect(found).toHaveLength(1);
expect(found[0].textContent).toMatch(/x/);
故意让测试失败

一个从未失败过的回归测试,尚未证明自己能测试任何内容。信任它之前,先强制让它变红,并阅读报错信息:

  • 在此软件包中修复 → 原地撤销该修复,确认测试因正确原因变红,然后恢复修复。
  • 跨软件包测试套件 → 将依赖重新固定到修复前的版本,确认测试变红,然后恢复固定版本。

在 PR 正文中记录观察到的失败输出。“它会变红”只是说法;报错信息才是证据。

加载同级软件包的源码进行真实集成测试

当一个缺陷是两个软件包共同作用的结果时,分别使用替代品测试会让它们都通过,但组合在一起时却会出错。要加载同级软件包的真实源码:

  1. 将其依赖固定到一个发布标签(例如 Git 依赖),这样测试套件测试的是已发布的制品,而不是不断变化的分支;
  2. 将其添加到 server.deps.inline 中——Vitest 默认会将 node_modules 外部化,并让 Node 直接处理原始 TypeScript:
export default defineConfig({
  test: { server: { deps: { inline: [/sibling-package/] } } },
});
  1. 导出宿主的真实入口点,让测试套件运行实际的代码路径,而不是可能无法复现该缺陷的单元测试接缝。

模拟(基本模式)

import { vi, test, expect } from 'vitest';

// Mock function
const mockFn = vi.fn();
mockFn.mockReturnValue(42);

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

// Mock timers
vi.useFakeTimers();
vi.advanceTimersByTime(1000);
vi.restoreAllMocks();

// Spy on method
const spy = vi.spyOn(object, 'method');

快照测试

test('snapshot test', () => {
  expect(data).toMatchSnapshot();
});

test('inline snapshot', () => {
  expect(result).toMatchInlineSnapshot('5');
});
// Update snapshots: bunx vitest -u

覆盖率

bun add --dev @vitest/coverage-v8
bunx vitest --coverage

关键配置选项:provider、reporter、include、exclude、thresholds。

Agent 优化

场景命令
快速测试bunx vitest --reporter=dot --bail=1
CI 测试bunx vitest run --reporter=junit
覆盖率检查bunx vitest --coverage --reporter=dot
单个文件bunx vitest run src/utils.test.ts --reporter=dot
仅运行失败项bunx vitest --changed --bail=1

如需详细示例、高级模式和最佳实践,请参阅 REFERENCE.md。

参考资料

评论

支持 Markdown