| name | unit-testing |
| description | This skill should be used when the user asks to "add unit tests", "write tests", "set up Vitest", "create a utility function", "add test coverage", or mentions TDD, test-driven development, or testing utilities. Provides guidance for unit testing with Vitest in TypeScript/Next.js projects using TDD approach. |
Unit Testing with Vitest
Scope: Unit tests only. See separate skills for integration/E2E.
TDD Workflow
RED → GREEN → REFACTOR
- RED: Write failing test first (function doesn't exist yet)
- GREEN: Write minimal code to pass
- REFACTOR: Clean up, run tests after each change
Setup
pnpm add -D vitest
Create vitest.config.mts:
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
include: ["**/*.test.ts"],
exclude: ["node_modules", ".next", ".content-collections", "e2e"],
},
});
Add to tsconfig.json:
{ "compilerOptions": { "types": ["vitest/globals"] } }
Add scripts:
{ "test": "vitest", "test:run": "vitest run" }
For complete setup options, see references/vitest-setup.md.
Test Structure
Place tests alongside code: myFunction.ts → myFunction.test.ts
import { describe, expect, it } from "vitest";
import { myFunction } from "./myFunction";
describe("myFunction", () => {
describe("valid inputs", () => {
it("handles primary case", () => {
expect(myFunction("input")).toBe("expected");
});
});
describe("invalid inputs", () => {
it("throws for bad input", () => {
expect(() => myFunction("bad")).toThrow();
});
});
});
Key Patterns
Zod validation - use safeParse:
it("rejects invalid", () => {
const result = Schema.safeParse(badData);
expect(result.success).toBe(false);
});
it("checks error message", () => {
const result = Schema.safeParse(badData);
if (!result.success) {
expect(result.error.errors[0].message).toContain("expected");
}
});
For mocking, async, parameterized tests, see references/test-patterns.md.
Run Tests
pnpm test:run # all tests
pnpm test:run lib/utils/myFunction.test.ts # specific file
pnpm test:run -t "pattern" # matching pattern
Checklist
- Tests cover primary use case
- Tests cover edge cases (empty, boundary)
- Tests cover error cases
- Descriptive test names
- Independent tests (no shared state)
- Mocks cleared (
vi.clearAllMocks()inbeforeEach) - All tests pass