| disable-model-invocation | false |
| name | vitest |
| user-invocable | true |
| description | Use for Vitest in TypeScript React/Next.js: write, run, or debug unit/component tests, mocks, testing utilities, and coverage. |
Your Role
You are an expert in writing tests with Vitest v4 for TypeScript React/Next.js projects. You help users write
high-quality tests, debug failures, and maintain test suites efficiently.
Typical setup:
- Vitest v4 with jsdom environment
- Globals enabled (
describe, test, expect, vi)
- Path aliases configured per project
Quick Start
Running Tests
nlx vitest run
nlx vitest run tokens
nlx vitest run src/utils/format.test.ts
nlx vitest run -t "adds token"
nlx vitest
Writing Your First Test
File naming: *.test.ts or *.test.tsx
Location: Colocate with source files
import { describe, test, expect } from "vitest";
import { myFunction } from "./my-function";
describe("myFunction", () => {
test("returns expected value", () => {
expect(myFunction(5)).toBe(10);
});
});
Project-Specific Patterns
Test Organization
Use visual separators and descriptive blocks:
describe("TokenStore", () => {
const validToken = { address: "0x123", symbol: "TEST" };
afterEach(() => {
useTokensStore.getState().clearAll();
});
describe("addToken", () => {
test("adds valid token and returns true", () => {
const success = useTokensStore.getState().addToken(validToken);
expect(success).toBe(true);
});
});
});
Cleanup Pattern
Always reset state in afterEach():
import { afterEach } from "vitest";
afterEach(() => {
vi.clearAllMocks();
process.env.NODE_ENV = originalEnv;
});
Factory Mock Pattern
Prefer factory functions for complex mocks:
import { vi } from "vitest";
export function createLocalStorageMock() {
const store = new Map<string, string>();
return {
getItem: vi.fn((key: string) => store.get(key) ?? null),
setItem: vi.fn((key: string, value: string) => {
store.set(key, value);
}),
removeItem: vi.fn((key: string) => {
store.delete(key);
}),
clear: vi.fn(() => {
store.clear();
})
};
}
import { createLocalStorageMock } from "./__mocks__/localStorage";
const mockStorage = createLocalStorageMock();
global.localStorage = mockStorage as Storage;
Shared Setup File
Global mocks and configuration live in a setup file (e.g., tests/setup.ts):
import { vi } from "vitest";
vi.mock("@/utils/logger", () => ({
createLogger: vi.fn(() => ({
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn()
}))
}));
Common Testing Scenarios
Testing Utilities
import { describe, test, expect, afterEach } from "vitest";
import { getEnvironment } from "./environment";
describe("getEnvironment", () => {
const originalEnv = process.env.NODE_ENV;
afterEach(() => {
process.env.NODE_ENV = originalEnv;
});
test("returns production when NODE_ENV is production", () => {
process.env.NODE_ENV = "production";
expect(getEnvironment()).toBe("production");
});
test("returns development by default", () => {
process.env.NODE_ENV = undefined;
expect(getEnvironment()).toBe("development");
});
});
Async Testing
test("async function resolves correctly", async () => {
const result = await fetchData();
expect(result).toEqual({ data: "value" });
});
test("async function rejects with error", async () => {
await expect(failingFunction()).rejects.toThrow("Error message");
});
Mocking
For function mocks (vi.fn, spyOn), module mocks (vi.mock, vi.doMock), and timer mocks (vi.useFakeTimers), see references/mocking.md.
Debugging Failed Tests
Reading Test Output
Focus on these signals:
- File and line number - Where the failure occurred
- Expected vs. received - What went wrong
- Stack trace - Ignore framework internals, focus on your code
Common Failures
For known failure modes and how to recover (timeouts, async assertions, mock not called, snapshot drift, etc.), see references/troubleshooting.md.
Debugging Tools
nlx vitest --reporter=verbose
nlx vitest --ui
nlx vitest --coverage
nlx vitest --inspect
nlx vitest --run
Best Practices
DO
- Colocate tests with source files (
feature.ts + feature.test.ts)
- Use
describe blocks to group related tests
- Add
afterEach() cleanup for state/mocks
- Use visual separators for clarity (
/* --- */)
- Test behavior, not implementation
- Use explicit type annotations for mocks
- Keep tests focused and independent
- Write tests before fixing bugs (reproduce the bug first)
DON'T
- Test implementation details (internal variables)
- Share state between tests
- Mock everything (only mock boundaries: network, storage, time)
- Forget to restore mocks/timers
- Use
any types in tests
- Create brittle tests tied to DOM structure
- Add backward-compatibility hacks for test utilities
Advanced Topics
For deeper dives, see the ./references/ directory:
testing-patterns.md - Complete pattern library (component tests, complex mocking, async patterns)
monorepo-testing.md - Workspace-specific strategies (shared vs. app tests, path aliases, organization)
troubleshooting.md - Debug guide (common errors, performance, coverage, CI/CD)
Coverage Analysis
To add coverage:
export default defineConfig({
test: {
coverage: {
provider: "v8",
reporter: ["text", "html", "json"],
exclude: ["**/*.test.ts", "**/__mocks__/**", "**/node_modules/**"]
}
}
});
Run with: nlx vitest --coverage
Configuration Reference
Example config: vitest.config.ts
{
environment: "jsdom",
globals: true,
include: ["**/*.test.{js,ts,tsx}"],
exclude: ["**/node_modules/**", "**/e2e/**"],
setupFiles: ["./tests/setup.ts"],
alias: {
"@": "./src",
},
}
Next Steps
- For component testing - See
./references/testing-patterns.md (React Testing Library setup)
- For monorepo-specific strategies - See
./references/monorepo-testing.md
- For debugging help - See
./references/troubleshooting.md
Start with simple unit tests, add component tests as needed.