Test file conventions: setup functions, factories, Result assertion helpers, organization, type testing, naming, and pruning low-value tests. Use when: "write tests", "add a test", "fix this test", "delete tests", "prune tests", "audit tests", or modifying *.test.ts files.
Test file conventions: setup functions, factories, Result assertion helpers, organization, type testing, naming, and pruning low-value tests. Use when: "write tests", "add a test", "fix this test", "delete tests", "prune tests", "audit tests", or modifying *.test.ts files.
metadata
{"author":"epicenter","version":"2.0"}
Test File Conventions
References
Load these on demand based on what you're working on:
If working with negative type tests (@ts-expect-error, bun:test type strategy, no as any), read references/type-testing.md
If working with test setup architecture (setup() patterns, composable setup, beforeEach avoidance, shared schemas), read references/setup-pattern.md
If working with test organization structure (flat tests, describe() boundaries, helper-over-nesting), read references/test-structure.md
If auditing existing tests for hedged assertions, pass-through getters, stalled fakes, dead fake surface, or docstrings that contradict the code, read references/honest-tests.md
Avoid local helper clones, expect(error).toBeNull() success checks, and
if (error) throw ... unwrapping when the value is a wellcrafted Result.
This rule does not apply to plain response bodies, UI snapshots, or other
objects that merely have an error property.
Tests vs. Benchmarks
Two distinct file extensions, two distinct purposes:
*.test.ts : asserts behavior with expect(). Runs under bun test
(repo default, CI). A test file without at least one expect() call does
not belong under this extension.
*.bench.ts : measures and reports. Prints tables, timings, or
storage sizes. Runs under bun bench only. No assertions required
(perf thresholds on shared hardware flake; prefer visual trends).
A single file is one or the other, never both. Benchmarks live under
src/__benchmarks__/ within a package; tests are colocated with the module
they cover. The bun test default-discovery glob picks up only *.test.ts
and friends, so renaming a report from .test.ts → .bench.ts is what
excludes it from CI.
File-Level Doc Comments
Every .test.ts file MUST start with a JSDoc block explaining what is being tested and the key behaviors verified. This serves as documentation for the module's contract.
Structure
/**
* [Module Name] Tests
*
* [1-3 sentences explaining what this file tests and why these tests matter.]
*
* Key behaviors:
* - [Behavior 1]
* - [Behavior 2]
* - [Behavior 3]
*
* See also:
* - `related-file.test.ts` for [related aspect]
*/
Good Example
/**
* Cell-Level LWW CRDT Sync Tests
*
* Verifies cell-level LWW conflict resolution where each field
* has its own timestamp. Unlike row-level LWW, concurrent edits to
* DIFFERENT fields merge independently.
*
* Key behaviors:
* - Concurrent edits to SAME field: latest timestamp wins
* - Concurrent edits to DIFFERENT fields: BOTH preserved (merge)
* - Delete removes all cells for a row
*/
Bad Example (Too Minimal)
// Tests for create-tables
Section Headers
For long test files (100+ lines), use comment headers to separate logical sections: