← Back to Docs
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.