# Test Style

> Defines deterministic behavioral tests and flaky-test red flags. Load when writing or reviewing `.test.ts` and `.evals.ts` files.

- Skill: `bostonaholic/test-style` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add bostonaholic/test-style`
- Raw SKILL.md: https://api.skillmd.com/api/skills/bostonaholic/test-style/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: bostonaholic (https://skillmd.com/u/bostonaholic)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/bostonaholic/test-style

---


# Test Style Rules

Before writing or reviewing tests, read [references/test-style-manual.md](references/test-style-manual.md).
It owns examples, language tools, the full audit bar, and every exception.

## Core rules

- Test observable behavior, not private calls. Interaction tests cover state changes only.
- Keep tests DAMP: linear arrange-act-assert, inputs visible, no test-body logic.
- Assert only the field or effect under test. Make failures actionable from name and output.
- Wait for conditions; never use fixed sleeps. Await every task; allow valid interleavings.
- Prefer real, then fake, then mock. Wrap vendor types behind owned interfaces.
- Reserve E2E for critical user journeys. Add cross-feature tests where behavior overlaps.

## Assert outcomes, not interleavings

Never depend on scheduler order. Use joins, awaits, barriers, or latches. Sort
or compare sets unless order is the contract.

## Control the clock

Freeze or inject time. Never feed real `new Date()`, `Date.now()`, naive calendar
math, future expiry literals, or timezone-naive dates into assertions.

```js
const token = { expiresAt: "2030-01-01" };
expect(isValid(token, new Date())).toBe(true);
```

```js
const now = new Date("2024-06-15T12:00:00Z");
const token = issueToken({ now, ttlDays: 30 });
expect(isValid(token, now)).toBe(true);
```

## Seed all randomness

Use explicit inputs or seed every RNG that can affect an assertion.

## Tests own their state — any order, any host

Each test creates and removes its DB rows, files, cache values, and environment
changes. Reset shared state. Never depend on another test or execution order.

## Impose order before asserting it

Use `ORDER BY` or sort before positional assertions. Otherwise use unordered
matchers. Never compare ordered expectations with set-backed results.

## Hermetic boundaries

Stub real networks; allocate ports dynamically; always close resources. Pin
locale, timezone, paths, and line endings. Compare floats with tolerance.

## Audit checklist

| Check | Pass criterion |
|---|---|
| Behavior-named | Name behavior, not a method. |
| Narrow assertion | Assert the specific contract. |
| Actionable failure | Output names the failed condition. |
| No sleeps | Use condition waits. |
| Deterministic inputs | Freeze clocks, seed RNGs, own state, order results, stub networks, allocate ports, close resources, pin environment, tolerate floats. |
| No test logic | No branches, loops, or string building. |
| One scenario per test | One independent behavior. |
| DAMP setup | Keep assertion-relevant setup visible. |
| Fidelity ladder | Real > fake > mock; wrap unowned types. |

## Flaky-test red flags (reviewer checklist)

Any outcome-dependent flag is blocking on first occurrence per `skills/reviewing-code/SKILL.md`:
real time or future dates; `sleep()` or timed waits; race order or missing awaits;
shared state or missing teardown; unseeded randomness; real networks; leaked resources or fixed ports; unordered positions; exact floats; platform, locale,
TZ, CPU, or CI parallelism. Fixed explicit-TZ dates and deterministic controls do not flag.

