home / skills / phrazzld / claude-config / vitest

vitest skill

/skills/vitest

This skill helps audit vitest.config.ts, optimize CI, and improve coverage and mocking through best practices for pools, isolation, and spying.

npx playbooks add skill phrazzld/claude-config --skill vitest

Review the files below or copy the command above to add this skill to your agents.

Files (5)
SKILL.md
2.3 KB
---
name: vitest
description: |
  Vitest configuration best practices for pools, performance, coverage, and mocking.
  Use when: auditing vitest.config.ts, optimizing CI, debugging test failures,
  configuring coverage, troubleshooting mocking, upgrading to Node 22+.
user-invocable: true
effort: high
---

# Vitest Best Practices

For test philosophy (behavior vs implementation, TDD workflow, when to mock), see `/testing-philosophy`.

## Critical Rules

1. **Node 22+**: Use `pool: 'forks'` - threads have known issues
2. **CI optimization**: Single worker, disable watch, enable `isolate: false` if safe
3. **Coverage**: Always define `coverage.include` - defaults exclude too much
4. **Mocking**: Prefer `vi.spyOn` over `vi.mock` - avoids hoisting footguns
5. **RTL cleanup**: Requires `globals: true` in config

## 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

```typescript
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

```typescript
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

```typescript
// 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](./references/pool-configuration.md) - threads vs forks vs vmThreads
- [Performance Patterns](./references/performance-patterns.md) - CI optimization, sharding
- [Coverage Strategy](./references/coverage-strategy.md) - v8 vs Istanbul, thresholds
- [Mocking Pitfalls](./references/mocking-pitfalls.md) - vi.mock hoisting, cleanup

Overview

This skill explains Vitest configuration best practices for pools, performance, coverage, and mocking. It highlights safe defaults for Node 22+, CI tuning, reliable coverage settings, and mocking patterns that avoid common hoisting pitfalls. Use it to audit vitest.config.ts, optimize CI runs, and stabilize tests during upgrades.

How this skill works

The skill inspects vitest test settings and recommends concrete config changes: pool selection (forks/threads/vmThreads), CI-focused flags (single worker, isolate), coverage provider and include rules, and mocking APIs. It flags risky defaults (threads on Node 22+, missing coverage include, vi.mock hoisting) and suggests minimal, actionable edits to vitest.config.ts for predictable behavior.

When to use it

  • Auditing vitest.config.ts during upgrades to Node 22+
  • Optimizing CI test runs for speed and predictability
  • Configuring coverage to ensure correct files are measured
  • Troubleshooting test flakiness caused by mocking or global leaks
  • Debugging failures where RTL globals or cleanup are missing

Best practices

  • On Node 22+, set pool: 'forks' to avoid native fetch and threads issues
  • For CI, use a single fork (singleFork: true), disable watch mode, and set isolate: false if tests are well isolated
  • Always specify coverage.include (e.g., ['src/**']) and use the v8 provider when supported
  • Prefer vi.spyOn for targeted mocking; avoid vi.mock unless module-level replacement is necessary
  • Enable globals: true for React Testing Library cleanup when using global helpers

Example use cases

  • Upgrade repo to Node 22+ and switch pool to 'forks' to prevent thread-related failures
  • Reduce CI flakiness by setting singleFork and isolate: false to make runs deterministic and faster
  • Fix missing coverage reports by adding coverage.include and using provider: 'v8'
  • Resolve a mysterious mock interaction by replacing vi.mock calls with vi.spyOn for explicit, non-hoisted spies
  • Tune a memory-sensitive CI by choosing vmThreads only when isolation is required and resources permit

FAQ

Why prefer forks on Node 22+?

Threads have known native fetch and runtime issues on Node 22+. Forks avoid those problems while remaining performant for most test suites.

When is vi.mock acceptable?

Use vi.mock when you must replace module initialization itself. For most call-level behavior changes, prefer vi.spyOn to avoid hoisting and import restrictions.