Recipes
Test Fixtures Patterns
Deterministic, isolated test data that makes your test suite fast and predictable.
Factory functions
Pure functions that return a fresh object with sensible defaults. Override only what the test cares about.
function createUser(overrides = {}) {
return {
id: crypto.randomUUID(),
email: "test@meridian.dev",
role: "member",
...overrides,
}
}Builder pattern
Chainable setters for complex entities. Each .with* method returns a new instance — never mutate.
class LicenseBuilder {
#data = { status: "active", seats: 1 }
withStatus(s) { return new LicenseBuilder({ ...this.#data, status: s }) }
withSeats(n) { return new LicenseBuilder({ ...this.#data, seats: n }) }
build() { return { ...this.#data } }
}Snapshot fixtures
Commit JSON blobs for integration tests. Version them alongside the code that consumes them.
// fixtures/hw-fingerprint.json
{
"diskSerial": "WD-ABCD1234",
"biosUuid": "550e8400-e29b-41d4-a716-446655440000",
"macAddr": "00:1A:2B:3C:4D:5E"
}Anti-patterns
- ✗Shared mutable state between tests — causes order-dependent flakes.
- ✗Real network calls in fixture setup — slow and brittle.
- ✗Fixtures that depend on other fixtures — creates a fragile chain.
Every fixture should be cheap to construct, isolated from I/O, and reproducible on any machine. Read the full guide in Testing Strategy.