domains / software-engineering / vitest-setup-and-testing / vitest
The copies cover different parts of the Vitest workflow. jezweb/claude-skills is a procedural setup skill that detects project type, installs dependencies, generates vitest.config.ts, and scaffolds test files. antfu/skills and LeoYeAI/openclaw-master-skills are reference catalogs that point to external reference files for API details, mocking, coverage, and workspaces. sickn33/agentic-awesome-skills provides inline patterns for writing tests, mocking, and in-source testing. No single copy contains the full procedure plus the reference material, so crowning one would hide real alternatives.
| Repository | Path |
|---|---|
| jezweb/claude-skills | plugins/dev-tools/skills/vitest/SKILL.md |
| antfu/skills | skills/vitest/SKILL.md |
| sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/vitest-skill/SKILL.md |
| LeoYeAI/openclaw-master-skills | skills/vitest/SKILL.md |
| Role | Repository | Path |
|---|---|---|
| peer | jezweb/claude-skills | plugins/dev-tools/skills/vitest/SKILL.md |
| peer | antfu/skills | skills/vitest/SKILL.md |
| peer | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/vitest-skill/SKILL.md |
| peer | LeoYeAI/openclaw-master-skills | skills/vitest/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills/skills/vitest-skill/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | skills/vitest-skill/SKILL.md |
---
name: vitest
description: "Set up Vitest testing in any project and write tests using Vitest's Jest-compatible API. Detects project type, generates vitest.config.ts, test setup, utilities, and sample tests. Covers mocking patterns, coverage config, workspace setup, Jest migration, and in-source testing. Use whenever the user mentions adding tests, setting up Vitest, configuring tests, migrating from Jest, fixing testing infrastructure, or asks 'how do I test this'."
license: MIT
---
# Vitest Setup and Testing
Detect the project type, generate the right Vitest configuration, produce working test infrastructure, and provide reference patterns for writing tests.
## Workflow
1. **Detect** — scan the project to determine type and existing setup
2. **Configure** — generate vitest.config.ts tailored to the environment
3. **Scaffold** — create test setup, utilities, and a sample test
4. **Wire up** — add package.json scripts and TypeScript config
5. **Write tests** — use Vitest API patterns for unit, component, and in-source tests
## Step 1: Detect Project Type
Read these files to determine the project:
```
package.json → dependencies, scripts, type field
tsconfig.json → paths, compiler options
wrangler.toml → Cloudflare Workers project
vite.config.ts → existing Vite setup (extend, don't replace)
vitest.config.ts → already configured? just fill gaps
jest.config.* → migration candidate
src/ → source structure
```
Classify as one of:
| Type | Signals | Environment |
|------|---------|-------------|
| **Cloudflare Workers** | wrangler.toml, @cloudflare/workers-types, cloudflare vite plugin | `node` with Workers-specific setup |
| **React (Vite)** | @vitejs/plugin-react, react-dom | `jsdom` or `happy-dom` |
| **React (SSR/TanStack Start)** | @tanstack/start, vinxi | Split: `node` for server, `jsdom` for client |
| **Node/Hono API** | hono, express, no react-dom | `node` |
| **Library** | exports field, no framework deps | `node` |
If a `vite.config.ts` already exists, extend it rather than creating a separate vitest.config.ts — Vitest reads Vite config natively.
## Step 2: Install Dependencies
Generate the install command based on detected type. Use the project's package manager (check for pnpm-lock.yaml, yarn.lock, bun.lockb, or package-lock.json).
```bash
# Base (always)
pnpm add -D vitest
# React projects — add jsdom and Testing Library
pnpm add -D @vitest/coverage-v8 jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
# Workers projects — add Cloudflare test utilities
pnpm add -D @vitest/coverage-v8 @cloudflare/vitest-pool-workers
# Node/Hono projects
pnpm add -D @vitest/coverage-v8
# If migrating from Jest, also remove:
pnpm remove jest ts-jest @types/jest jest-environment-jsdom babel-jest
```
## Step 3: Generate vitest.config.ts
### Cloudflare Workers
```typescript
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
export default defineWorkersConfig({
test: {
globals: true,
poolOptions: {
workers: {
wrangler: { configPath: "./wrangler.toml" },
},
},
},
});
```
If the project uses the Cloudflare Vite plugin (`@cloudflare/vite-plugin`), integrate into the existing vite.config.ts instead:
```typescript
/// <reference types="vitest/config" />
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({
plugins: [cloudflare()],
test: {
globals: true,
},
});
```
### React (Vite)
```typescript
/// <reference types="vitest/config" />
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./src/test/setup.ts"],
css: true,
},
});
```
If a vite.config.ts already exists, add the `test` block to it rather than creating a new file.
### Node / Hono API
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
},
});
```
### With Coverage (add to any config)
```typescript
test: {
// ... existing config
coverage: {
provider: "v8",
reporter: ["text", "html", "lcov"],
exclude: [
"node_modules/",
"**/*.config.*",
"**/*.d.ts",
"**/test/**",
],
},
},
```
## Step 4: Generate Test Setup File
Create `src/test/setup.ts` (React projects only):
```typescript
import "@testing-library/jest-dom/vitest";
```
That single import adds all the custom matchers (toBeInTheDocument, toHaveTextContent, etc.) and registers the Vitest `expect.extend` automatically.
## Step 5: Add TypeScript Config
Add to `tsconfig.json` compilerOptions:
```json
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
```
For projects with multiple tsconfig files (e.g. tsconfig.app.json + tsconfig.node.json), add to the one that covers test files — usually the root tsconfig.json or create a tsconfig.test.json that extends it.
## Step 6: Add Package.json Scripts
```json
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"test:ui": "vitest --ui"
}
}
```
Don't overwrite existing scripts — merge with what's there.
## Step 7: Generate Sample Test
Write one test file that demonstrates the right patterns for this specific project. Place it next to real source code, not in a separate `__tests__` directory.
### For a Hono API route (e.g. `src/routes/health.ts`):
```typescript
import { describe, it, expect } from "vitest";
import { app } from "../index";
describe("GET /health", () => {
it("returns 200 with status ok", async () => {
const res = await app.request("/health");
expect(res.status).toBe(200);
const body = await res.json();
expect(body).toEqual({ status: "ok" });
});
});
```
### For a React component (e.g. `src/components/Button.tsx`):
```typescript
import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import Button from "./Button";
describe("Button", () => {
it("renders with label", () => {
render(<Button label="Click me" />);
expect(screen.getByText("Click me")).toBeDefined();
});
});
```
## Test Writing Patterns
### Basic Test
```typescript
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { Calculator } from './calculator';
describe('Calculator', () => {
let calc: Calculator;
beforeEach(() => { calc = new Calculator(); });
it('adds two numbers', () => {
expect(calc.add(2, 3)).toBe(5);
});
it('throws on divide by zero', () => {
expect(() => calc.divide(10, 0)).toThrow();
});
});
```
### Mocking (vi instead of jest)
```typescript
import { vi } from 'vitest';
// Mock module
vi.mock('./database', () => ({
getUser: vi.fn().mockResolvedValue({ name: 'Alice' }),
saveUser: vi.fn().mockResolvedValue(true),
}));
// Mock function
const mockFn = vi.fn();
mockFn.mockReturnValue(42);
mockFn.mockResolvedValue({ data: 'test' });
// Spy
const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
expect(spy).toHaveBeenCalledWith('message');
spy.mockRestore();
// Timers
vi.useFakeTimers();
vi.advanceTimersByTime(1000);
vi.runAllTimers();
vi.useRealTimers();
```
### In-Source Testing
```typescript
// src/math.ts — tests alongside code!
export function add(a: number, b: number) { return a + b; }
export function multiply(a: number, b: number) { return a * b; }
if (import.meta.vitest) {
const { it, expect } = import.meta.vitest;
it('adds', () => { expect(add(2, 3)).toBe(5); });
it('multiplies', () => { expect(multiply(3, 4)).toBe(12); });
}
```
### Snapshot Testing
```typescript
it('serializes user', () => {
expect(serializeUser(user)).toMatchSnapshot();
});
it('inline snapshot', () => {
expect(serializeUser(user)).toMatchInlineSnapshot(`
{ "name": "Alice", "email": "alice@test.com" }
`);
});
```
### Anti-Patterns
| Bad | Good | Why |
|-----|------|-----|
| `jest.fn()` | `vi.fn()` | Vitest uses `vi` |
| `jest.mock()` | `vi.mock()` | Different namespace |
| No type safety | TypeScript + strict | Vitest is TS-first |
## Quick Reference
| Task | Command |
|------|---------|
| Run once | `npx vitest run` |
| Watch | `npx vitest` (default) |
| UI | `npx vitest --ui` |
| Coverage | `npx vitest --coverage` |
| Specific file | `npx vitest run src/math.test.ts` |
| Filter | `npx vitest run -t "adds"` |
## Reference Topics
For detailed API and feature references, consult the Vitest documentation or the reference files listed in the antfu/skills catalog:
- Configuration: Vitest and Vite config integration, defineConfig usage
- CLI: Command line interface, commands and options
- Test API: test/it function, modifiers like skip, only, concurrent
- Describe API: describe/suite for grouping tests and nested suites
- Expect API: Assertions with toBe, toEqual, matchers and asymmetric matchers
- Hooks: beforeEach, afterEach, beforeAll, afterAll, aroundEach
- Mocking: Mock functions, modules, timers, dates with vi utilities
- Snapshots: Snapshot testing with toMatchSnapshot and inline snapshots
- Coverage: Code coverage with V8 or Istanbul providers
- Test Context: Test fixtures, context.expect, test.extend for custom fixtures
- Concurrency: Concurrent tests, parallel execution, sharding
- Filtering: Filter tests by name, file patterns, tags
- Test Tags: Label tests with tags to filter runs and apply shared options
- Reporters: Built-in reporters, default selection, CI/output config
- Benchmarking: Write benchmarks with the bench fixture (Tinybench)
- Vi Utilities: vi helper: mock, spyOn, fake timers, hoisted, waitFor
- Environments: Test environments: node, jsdom, happy-dom, custom
- Type Testing: Type-level testing with expectTypeOf and assertType
- Projects: Multi-project workspaces, different configs per project
## Limitations
- Use this skill only when the task clearly matches its upstream source and local project context.
- Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.
- Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.