Generating Fake JSON Fixtures for Jest and Vitest Unit Tests

July 6, 2026

Inline test data — a literal object typed directly into a test file — works fine for the first test. By the tenth test reusing slightly different copies of the same shape, you've got duplicated, drifting data scattered across your suite. Fixture files fix this, and generating them properly up front saves hours of later maintenance.


Step 1: Generate a Base Fixture Set

Build your core dataset — the shape your functions and components actually consume — in Dummy JSON Generator and save it under a __fixtures__ or test/fixtures directory.

// __fixtures__/orders.json
[
  { "id": 101, "status": "shipped", "total": 42.50, "items": 2 },
  { "id": 102, "status": "pending", "total": 15.00, "items": 1 },
  { "id": 103, "status": "cancelled", "total": 0, "items": 0 }
]

Step 2: Use Factory Functions, Not Static Objects, for Per-Test Variation

Static fixtures are great for "give me a realistic dataset," but individual tests usually need one field changed — a factory function lets you do that without duplicating the whole object.

// test/factories/order.ts
import baseOrders from '../../__fixtures__/orders.json'

export function makeOrder(overrides: Partial<typeof baseOrders[0]> = {}) {
  return { ...baseOrders[0], ...overrides }
}

// usage in a test:
const cancelledOrder = makeOrder({ status: 'cancelled', total: 0 })

This pattern — sometimes called the "object mother" or factory pattern — keeps every test's intent readable: you can see exactly which field was overridden and why, without re-declaring the entire object.


Step 3: Write the Test Against the Fixture

import { describe, it, expect } from 'vitest'
import { calculateOrderTotal } from '../src/orders'
import { makeOrder } from './factories/order'

describe('calculateOrderTotal', () => {
  it('returns 0 for a cancelled order', () => {
    const order = makeOrder({ status: 'cancelled', total: 42.5 })
    expect(calculateOrderTotal(order)).toBe(0)
  })

  it('returns the stored total for a shipped order', () => {
    const order = makeOrder({ status: 'shipped', total: 42.5 })
    expect(calculateOrderTotal(order)).toBe(42.5)
  })
})

The exact same fixture and factory work unchanged in Jest — the API surface (describe, it, expect) is identical between the two runners.


Step 4: Snapshot Testing with Generated Fixtures

For components or serializers where you want to catch any structural change, snapshot testing pairs well with generated fixtures — since the fixture is stable and version-controlled, snapshot diffs only fire when your actual code output changes, not because the input data shifted randomly.

it('matches the invoice snapshot', () => {
  const invoice = formatInvoice(makeOrder())
  expect(invoice).toMatchSnapshot()
})

Important: never generate fresh random data inside a snapshot test — random values (dates, UUIDs, `Math.random()`) will fail the snapshot on every run. Fixtures need to be static and committed to the repo, not regenerated at test time.


Common Pitfalls

  • Mutating shared fixtures: if one test mutates the imported fixture object directly, later tests in the same file see the mutated version. Always spread into a new object (as the factory function above does) rather than mutating the import.
  • One giant fixture file for everything: split fixtures by domain (orders.json, users.json) so tests only import what they need and changes stay localized.
  • Fixtures that don't match the real API shape: regenerate fixtures whenever the real API contract changes — stale fixtures give you false test confidence.

The Bottom Line

Generate a realistic base fixture set once, wrap it in a factory function for per-test overrides, and keep fixtures static and committed rather than randomly regenerated — that combination keeps Jest and Vitest suites both readable and reliable as they grow.