一键导入
vitest
Vitest 4.x 測試框架最佳實踐指南。當需要設定測試、撰寫單元/元件測試、mocking、coverage、整合 Astro/Three.js 測試時使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Vitest 4.x 測試框架最佳實踐指南。當需要設定測試、撰寫單元/元件測試、mocking、coverage、整合 Astro/Three.js 測試時使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | vitest |
| description | Vitest 4.x 測試框架最佳實踐指南。當需要設定測試、撰寫單元/元件測試、mocking、coverage、整合 Astro/Three.js 測試時使用。 |
toMatchScreenshot()、expect.schemaMatching、expect.assertnpm install -D vitest @vitest/coverage-v8
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
globals: true,
include: ['src/**/*.{test,spec}.{ts,tsx}'],
exclude: ['node_modules', 'dist', 'e2e'],
restoreMocks: true, // 自動還原 mock
pool: 'forks', // 預設,最安全
coverage: {
provider: 'v8',
include: ['src/**/*.ts'],
exclude: ['src/**/*.d.ts', 'src/**/*.test.ts'],
thresholds: { statements: 80, branches: 80, functions: 80, lines: 80 },
},
},
});
import { getViteConfig } from 'astro/config';
export default getViteConfig({
test: { /* vitest options */ },
});
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import Card from '../src/components/Card.astro';
test('Card renders', async () => {
const container = await AstroContainer.create();
const html = await container.renderToString(Card, {
slots: { default: 'content' },
});
expect(html).toContain('content');
});
const handler = vi.fn();
handler('arg');
expect(handler).toHaveBeenCalledWith('arg');
const spy = vi.spyOn(console, 'log');
doSomething();
expect(spy).toHaveBeenCalledWith('expected');
vi.mock('./api', () => ({
fetchData: vi.fn().mockResolvedValue({ id: 1 }),
}));
| 方法 | 效果 |
|---|---|
mockClear() | 清除呼叫記錄 |
mockReset() | 清除 + 移除實作 |
mockRestore() | 還原原始(僅 spy) |
建議:設定 restoreMocks: true 自動還原。
it('fetches data', async () => {
const data = await fetchUser(1);
expect(data.name).toBe('Alice');
});
it('debounce', () => {
vi.useFakeTimers();
const fn = vi.fn();
debounce(fn, 300)();
vi.advanceTimersByTime(300);
expect(fn).toHaveBeenCalledOnce();
vi.useRealTimers();
});
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'test' }),
}));
WebGL 在 Node.js 不可用,策略:
vi.mock('three', async (importOriginal) => {
const actual = await importOriginal<typeof import('three')>();
return {
...actual,
WebGLRenderer: vi.fn().mockImplementation(() => ({
setSize: vi.fn(),
render: vi.fn(),
domElement: document.createElement('canvas'),
dispose: vi.fn(),
setPixelRatio: vi.fn(),
})),
};
});
原則:將場景邏輯(物件位置、層級、材質)與渲染分開測試。Mock WebGLRenderer,專注測試 scene graph。
vi.mock('node:fs/promises', () => ({
readFile: vi.fn().mockResolvedValue('content'),
writeFile: vi.fn().mockResolvedValue(undefined),
}));
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve([{ id: 1 }]),
}));
import { collectData } from './collect';
it('collects data', async () => {
const result = await collectData();
expect(result).toHaveLength(1);
});
export default defineConfig({
test: {
projects: [
{
extends: true,
test: { name: 'unit', include: ['src/**/*.unit.test.ts'], environment: 'node' },
},
{
extends: true,
test: { name: 'components', include: ['src/**/*.component.test.ts'], environment: 'jsdom' },
},
],
},
});
執行特定 project:vitest --project unit
| v8(預設) | Istanbul | |
|---|---|---|
| 速度 | 較快 | 較慢 |
| 安裝 | @vitest/coverage-v8 | @vitest/coverage-istanbul |
| 適用 | V8 runtime(Node.js) | 所有 JS runtime |
建議用 v8。忽略特定行:/* v8 ignore next */
// 單檔覆蓋
// @vitest-environment happy-dom
expect(result).toMatchSnapshot(); // 檔案 snapshot
expect(result).toMatchInlineSnapshot(); // inline(自動填入)
expect(html).toMatchFileSnapshot('./expected.html'); // 自訂檔案
更新:vitest -u
export function add(a: number, b: number) { return a + b; }
if (import.meta.vitest) {
const { it, expect } = import.meta.vitest;
it('adds', () => expect(add(1, 2)).toBe(3));
}
設定:includeSource: ['src/**/*.ts']
Production 移除:define: { 'import.meta.vitest': 'undefined' }
| 策略 | 做法 |
|---|---|
| Pool | threads(大專案)、forks(預設,安全) |
| 停用隔離 | isolate: false(無副作用時) |
| 限縮搜尋 | dir: 'src' |
| CI 分片 | --shard=1/4 + --merge-reports |
forksforksvite-tsconfig-pathsexpect().rejects 處理預期錯誤檔名:*.test-d.ts,執行:vitest --typecheck
import { expectTypeOf } from 'vitest';
expectTypeOf(add).parameter(0).toBeNumber();
expectTypeOf(add(1, 2)).toEqualTypeOf<number>();
Zod v4 schema validation 最佳實踐指南。當需要定義 schema、驗證/解析 JSON 資料、type inference、或處理 unknown data 時使用。
Svelte 5 + Astro 整合最佳實踐指南。當需要建立 Svelte 元件、使用 runes API、整合 Astro islands、或用 Testing Library 測試 Svelte 元件時使用。
GitHub GraphQL API 最佳實踐指南。當需要使用 GraphQL 查詢使用者資料、處理 cursor pagination、計算 rate limit、或除錯 GraphQL errors 時使用。
gayanvoice/top-github-users 架構參考指南。當需要了解 GitHub 使用者排行榜的資料抓取管線、國家設定、排行計算邏輯、已知問題、或社群需求時使用。
Commander.js v14 CLI 框架最佳實踐。當需要建立 CLI 工具、解析命令列參數、設計 subcommands 時使用。
GitHub Actions CI/CD 最佳實踐指南。當需要設定 workflow、cron 排程、GitHub Pages 部署、使用 Octokit API、或處理 rate limiting 時使用。