---
applyTo: "**/*.test.*,**/*_test.*,**/test_*.*,**/tests/**,**/__tests__/**"
description: "Testing conventions for this project"
---

# Testing Conventions

## Structure

Use Arrange-Act-Assert:

```ts
test('userService.create returns the new user when input is valid', async () => {
  // Arrange
  const input = makeUserInput();
  // Act
  const user = await userService.create(input);
  // Assert
  expect(user.id).toBeDefined();
});
```

Test names follow the form `<scope> <verb> <expected> when <condition>`.

## Rules

- Write a failing test **before** fixing a bug.
- One assertion per test (or closely related assertions on the same outcome).
- Mock at boundaries only: HTTP, database, filesystem, external APIs.
- Do not mock the unit under test.
- Do not test framework internals, getters/setters, or trivial pass-throughs.

## Coverage

- All new business logic has tests.
- Critical paths have happy-path and at least one error-case test.
- Long-running or flaky tests live in a separate `e2e/` or `integration/` directory, not unit suites.

## Test Data

- Use factory functions (`makeUser()`, `makeOrder()`) rather than inline literals.
- Keep fixtures in `tests/fixtures/`.
- Never commit real production data.

## Failure Messages

Prefer matchers that give actionable output:

- `toEqual` over `toBe` for objects.
- `toMatchObject` when only a subset matters.
- Custom messages on critical assertions when the matcher output is opaque.
