Write Tests
Write the appropriate unit, integration, component, and end-to-end tests: $ARGUMENTS
Process
Follow these steps in order:
Understand the project's test conventions
- Identify the language, runtime, package boundary, and every test runner relevant to the requested tests
- Inspect dependencies, imports, runner configuration, package scripts, setup files, CI commands, and representative existing tests
- Load every matching language and runner reference that exists:
references/junit.mdreferences/typescript.mdreferences/vitest.mdreferences/jest.mdreferences/node-test.mdreferences/bun-test.mdreferences/playwright.md
- In monorepos and migrations, determine runner ownership per package and test file; do not assume one runner governs the repository
- Repository conventions and installed-version behavior override greenfield defaults
Analyse the code under test
- Identify the public interface and critical business logic
- Map dependencies and external interactions
- Note error conditions, edge cases, and validation rules
- Follow repository coverage thresholds and use coverage to identify consequential gaps rather than gaming a universal percentage
Plan the test strategy
- Decide which levels are needed: unit, integration, end-to-end
- List what to mock or stub, and why
- Prioritise business-critical paths first
Write unit tests
- Test cohesive units through the smallest stable public or package boundary; tests do not need to map one-to-one to functions or methods
- Cover relevant happy paths, edge cases, boundary conditions, and error/exception paths
- Follow the AAA pattern (Arrange / Act / Assert) — use blank lines to separate phases, never write
// Arrangecomments - Use descriptive test names that explain the scenario being tested
- Keep each test focused on one behaviour; avoid assertions on unrelated state
Write integration tests
- Test real interactions among application-owned components and controlled dependencies such as in-process APIs, test databases, sandboxes, or contract servers
- Do not contact production or uncontrolled live third-party services by default
- Verify data flow across meaningful layer boundaries
- Cover failure modes and partial failures, not just the happy path
Write component or end-to-end tests when needed
- Exercise observable user behavior through framework-supported test APIs
- Keep critical cross-boundary flows in E2E tests and lower-level edge cases in faster tests
- Preserve accessibility, isolation, cleanup, and supported runtime/browser coverage
Mocking and test data
- Mock external dependencies to keep unit tests fast and deterministic
- Avoid over-mocking — if a mock replicates production logic, use a real object instead
- Use factories or builders for complex test data; keep setup out of assertion code
- Ensure tests are isolated — no shared mutable state between cases
Apply applicable specialist concerns
- Async code: use the framework's async test utilities; test both resolution and rejection
- Security: cover auth checks, input validation, and access control boundaries
- UI: test rendered output, keyboard navigation, and ARIA semantics where relevant