Writing Tests
Use this skill when the user asks to add tests to existing code, improve test coverage, or write tests for a specific file or module.
Steps
Detect the test setup — check what's already configured:
# Check package.json for test runner cat package.json | grep -E "jest|vitest|mocha|playwright|cypress"Look for config files:
vitest.config.ts,jest.config.ts,playwright.config.ts,.mocharc.*. Check for existing test files to understand the project's test patterns and conventions.If no test runner exists — set one up:
npm install -D vitest @testing-library/react @testing-library/jest-domAdd a
testscript topackage.json:{ "test": "vitest run", "test:watch": "vitest" }Analyze the target code — read the file(s) to test and identify:
- Public API: exported functions, classes, components, hooks
- Code paths: conditionals, error handling, edge cases
- Dependencies: external services, databases, APIs that need mocking
- Side effects: file I/O, network calls, DOM mutations
Create the test file — place it next to the source file or in a
__tests__/directory, matching the project's convention:src/utils/format.ts→src/utils/format.test.tssrc/components/Button.tsx→src/components/Button.test.tsx
Write tests following this structure:
import { describe, it, expect, vi } from "vitest"; describe("functionName", () => { // Happy path it("returns formatted output for valid input", () => { ... }); // Edge cases it("handles empty string", () => { ... }); it("handles null/undefined input", () => { ... }); // Error cases it("throws on invalid argument", () => { ... }); // Boundary conditions it("handles maximum length input", () => { ... }); });Mock external dependencies — don't make real API calls or database queries in unit tests:
vi.mock("@/lib/db", () => ({ query: vi.fn().mockResolvedValue([{ id: 1, name: "test" }]), }));For React components, mock hooks that fetch data:
vi.mock("@/hooks/useUser", () => ({ useUser: () => ({ user: { name: "Test" }, isLoading: false }), }));Test React components with Testing Library:
import { render, screen, fireEvent } from "@testing-library/react"; it("renders the button and handles click", () => { const render(<Button me</Button>); fireEvent.click(screen.getByRole("button", { name: "Click me" })); expect(onClick).toHaveBeenCalledOnce(); });Run the tests and verify they pass:
npm testIf any fail, fix the test or the code (depending on whether the test expectation or the implementation is wrong).
What to Test
- Always test: public API, error handling, edge cases (empty, null, zero, negative), state transitions, async behavior
- Skip testing: private implementation details, third-party library internals, simple getters/setters, type-only code
Notes
- Match the project's existing test style — if they use
test()instead ofit(), follow that. - Don't test implementation details — test behavior and outputs, not internal method calls.
- Use descriptive test names that explain the scenario: "returns 0 when cart is empty" not "test1".
- One assertion concept per test — multiple
expectcalls are fine if they verify the same behavior. - For async code, always
awaitthe result or useresolves/rejectsmatchers.