unit-testing
Unit Testing
Conventions
- Co-locate tests:
foo.test.tsnext tofoo.ts - Always wrap in
describenamed after the unit under test - Use
test, notit - Test behavior through public interfaces, not implementation details
- Good tests survive refactors — if the public API doesn't change, tests shouldn't break
describe("createCart", () => {
test("calculates total for multiple items", () => { ... });
test("returns empty items for new cart", () => { ... });
});
Vitest API
import { describe, expect, test, vi } from "vitest";
| API | Use |
|---|---|
describe("group", fn) |
Group related tests |
test("desc", fn) |
Single test |
test.each([...])("desc %s", fn) |
Parameterized |
expect(v).toBe(x) |
Strict equality |
expect(v).toEqual(x) |
Deep equality |
expect(fn).toThrow() |
Assert throws |
vi.fn() |
Mock function |
Mocking Rules
Mock only at system boundaries:
- External APIs, databases, time (
Date.now), randomness (Math.random), file system
Never mock things you control:
- Your own modules, internal collaborators, utility functions, data transformations
If you feel the need to mock an internal module, the code is doing too much or you're testing at the wrong level.
For mocking patterns and DI examples, see references/mocking.md.
Coverage
When a project has coverage thresholds configured, every file must meet them individually (perFile: true). Write tests that cover all branches and statements — if a file has unreachable code, that's a signal to simplify the implementation rather than lower thresholds.
Acceptance Checklist
- Test describes behavior, not implementation
- Test uses the public interface
- Test would survive an internal refactor
- Mocks only at system boundaries
- Co-located next to source file
- Coverage thresholds pass for the file under test
More from kvnwolf/devtools
commit
Wraps up work by syncing documentation, committing, pushing, and opening a pull request. Use when committing code, finishing a task, pushing changes, or creating a PR.
10base
Scaffolds a new TypeScript project from scratch. Use when starting a new project, bootstrapping a codebase, or setting up a project from zero.
10convex
Provides instructions for working with Convex backend projects. Use when setting up Convex, creating queries/mutations/actions, consuming Convex data from React, defining tables, testing Convex functions, configuring environment variables, or prefetching data in route loaders.
7e2e-testing
Writes end-to-end tests with Playwright Test for full user flow verification. Use when adding, modifying, or removing user flows in an application. Do not use for isolated component behavior — use component-testing instead.
5tanstack-start
Provides instructions for working with TanStack Start projects. Use when setting up, configuring, developing, creating routes, or creating server functions in a TanStack Start application.
5create-skill
Creates or modifies agent skills, including single-workflow and multi-workflow (orchestrator) skills. Use when the user wants to create, write, author, scaffold, edit, update, fix, or refactor a skill, or migrate a skill from single to multi-workflow.
5