Test Writer Skill (Vitest + RTL)
Process
- Identify what's being tested: pure function → unit test in
src/**/*.test.tsnext to the source file; component →*.test.tsxnext to the component; API route/Server Action → integration test insrc/**/__tests__/or co-located. - Cover, at minimum: the happy path, one validation/error path, and any edge case explicitly mentioned by the user or visible in the code (empty arrays, null, boundary numbers).
- For components, query by accessible role/label/text (
getByRole,getByLabelText) — fall back todata-testidonly when there is no accessible query available. - For async behavior, use
findBy*queries orwaitFor, never arbitrarysetTimeout. - For Server Actions/API routes, mock the database layer at the module boundary (e.g.
vi.mock('@/server/db')) rather than hitting a real database. - Run
pnpm test <path>after writing to confirm the test passes (and would have failed before the fix, for regression tests).
Test skeleton
import { describe, it, expect, vi } from "vitest";
describe("<unit under test>", () => {
it("does the expected thing on the happy path", () => {
// arrange, act, assert
});
it("handles the error/edge case", () => {
// arrange, act, assert
});
});
Checklist
- Happy path covered
- At least one failure/edge case covered
- No arbitrary
setTimeout/sleep in async tests - Mocks isolated at module boundary, not deep internals
-
pnpm testpasses locally