vitest
SKILL.md
Vitest Best Practices
For test philosophy (behavior vs implementation, TDD workflow, when to mock), see /testing-philosophy.
Critical Rules
- Node 22+: Use
pool: 'forks'- threads have known issues - CI optimization: Single worker, disable watch, enable
isolate: falseif safe - Coverage: Always define
coverage.include- defaults exclude too much - Mocking: Prefer
vi.spyOnovervi.mock- avoids hoisting footguns - RTL cleanup: Requires
globals: truein config
Memory Safety (MANDATORY)
Vitest in watch mode holds ~2 GB per process. 12 repos = 24+ GB = machine crash.
| Rule | Why |
|---|---|
"test" script MUST be vitest run, never bare vitest |
Bare vitest = watch mode = persistent process |
Hook/CI subprocesses: env={**os.environ, "CI": "true"} |
Belt-and-suspenders against watch mode |
Pool config: forks, maxForks: 4 on <=36 GB |
Caps memory at ~2 GB total |
Never run vitest --watch from automated/agent contexts |
Zombies accumulate across sessions |
| Never delegate >3 parallel agents from hooks/scripts | Each agent spawns its own Node processes |
When onboarding a new repo, check package.json test script immediately.
Quick Reference
Pool Selection (Node 22+)
| Pool | Use When | Avoid When |
|---|---|---|
forks |
Node 22+, default choice | - |
threads |
Node <22, CPU-bound tests | Node 22+ (native fetch issues) |
vmThreads |
Need isolation + speed | Memory-constrained CI |
CI Configuration
export default defineConfig({
test: {
pool: 'forks',
poolOptions: {
forks: {
singleFork: true, // CI: predictable, less overhead
},
},
isolate: false, // Faster if tests don't leak state
reporters: ['verbose'],
coverage: {
reportOnFailure: true,
},
},
})
Coverage Quick Reference
coverage: {
provider: 'v8', // Accurate in Vitest 3.2+
include: ['src/**'], // ALWAYS define - defaults miss files
reporter: ['text', 'lcov'],
reportOnFailure: true, // Get coverage even on test failure
}
Mocking Quick Reference
// PREFER: vi.spyOn - explicit, no hoisting issues
const spy = vi.spyOn(service, 'method').mockReturnValue('mocked')
// AVOID unless necessary: vi.mock - hoisted, can't use imports
vi.mock('./module', () => ({ fn: vi.fn() }))
Reference Files
- Pool Configuration - threads vs forks vs vmThreads
- Performance Patterns - CI optimization, sharding
- Coverage Strategy - v8 vs Istanbul, thresholds
- Mocking Pitfalls - vi.mock hoisting, cleanup
Weekly Installs
19
Repository
phrazzld/claude-configGitHub Stars
5
First Seen
Feb 5, 2026
Security Audits
Installed on
gemini-cli19
opencode19
codebuddy19
github-copilot19
codex19
kimi-cli19