vitest
Write and optimize Vitest unit and component test suites; configure workspace projects, worker thread pools, mocks, coverage, and instant watch mode.
Files3
View on GitHubSKILL.mdskills/vitest/SKILL.md
GitHubVitest High-Performance Testing AI Skill Guide (Claude)
Overview & Engine Architecture
Vitest reuses Vite's transform pipeline for fast ESM/TS tests. Tests run in a pool (forks default in Vitest 2+, or threads) with per-file isolation by default—each file gets a clean module registry unless isolate: false.
Claude operates as a Principal Quality Engineer: mock reset discipline, fork isolation vs speed tradeoffs, fake timers, and coverage thresholds in CI.
vitest.config.ts
→ pool (forks | threads | vmThreads)
→ per-file isolation (default true)
→ happy-dom/jsdom for components
→ v8 coverage + thresholds
When to use / when not to
Use when
- Vite, Vitest-native, or Next.js projects already on Vite tooling.
- Fast watch mode and ESM-native mocking.
Do not use when
- Jest is mandated with custom transformers the team won't migrate—don't dual-run without reason.
Operational Capabilities & Agent Directives
- Default
pool: 'forks'for stability; switch tothreadsonly after green CI with isolation on. isolate: falseis opt-in speed—requiresrestoreMocks, no leakingvi.mockacross files; expect order-dependent bugs if careless (GitHub #9499, #11152).clearMocks/mockReset/restoreMocksin config orafterEach; callvi.useRealTimers()after fake timers.- No real sleeps—
vi.useFakeTimers()+vi.advanceTimersByTime. - Path aliases must match Vite (
resolve.aliasorvite-tsconfig-paths). - CI cores: cap
poolOptions.forks.maxThreadson 2-core runners. process.nextTickmocking incompatible withpool: forks—use threads if you must mock it.
Production config sketch
import { defineConfig } from "vitest/config";
import path from "node:path";
export default defineConfig({
resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
test: {
environment: "happy-dom",
pool: "forks",
isolate: true,
restoreMocks: true,
coverage: {
provider: "v8",
thresholds: { lines: 85, branches: 80 },
},
},
});
Mock + timers:
beforeEach(() => {
vi.useFakeTimers();
vi.clearAllMocks();
});
afterEach(() => {
vi.useRealTimers();
});
Technical Troubleshooting Matrix
| Issue | Root cause | Fix |
|---|---|---|
document is not defined |
No DOM env | environment: 'happy-dom' |
| Flaky parallel failures | Shared module mock with isolate: false |
Re-enable isolation or fix mock scope |
| Wrong mock in unrelated file | Module cache + isolate: false |
pool: forks + isolate: true |
Can't find @/ |
Missing alias | vitest resolve.alias |
| CI OOM / slow | Too many threads | Lower maxThreads |
Best practices
- Share Vite plugins with app config via merged
defineConfig. - Prefer
vi.spyOnfor partial mocks when factories leak across files. - Component tests: Testing Library + roles.
- Run
vitest run --coveragein CI; watch locally.
Limitations
- Not a browser E2E runner—pair with
@playwright. - Native modules may require forks over threads.
- Snapshot churn—review intentionally, don't blind
-uin CI.
Related skills
@react— component behavior under test@nextjs— vitest + Next monorepo setup@playwright— E2E layer above unit tests
Agent Operational Directive
MANDATORY: Keep default file isolation unless the suite proves clean teardown. Reset mocks and timers between tests. Never use real
setTimeoutsleeps for assertions. Treatisolate: falseflakiness as a test design bug, not "Vitest randomness."