Skip to content
Logo

Quick start

This library is particularly useful for defining test fixtures to exercise your code with inputs that you may not have anticipated. In this way, it facilitates a form of fuzzing.

import {  } from "@ghostry/fabricator";
 
const { ,  } = ();
 
const  = .({
  : ..({ : { : 1, : 25 } }),
  : ..({ : 1, : 500 }),
  : .,
  : ..,
  : .(..({ : { : 15 } })).({
    : { : 5 },
  }),
});
 
const  = new ();
 
const  = .();
// { name: "...", price: ..., inStock: ..., createdAt: ..., tags: [...] }

That's the whole loop:

  1. initialize(...) gives you T (a namespace of type builders) and Fabricator (a constructor for turning a Schema into something live).
  2. T.object({ ... }) builds a Schema — inert, serializable data describing a shape. Building it draws no randomness.
  3. new Fabricator(schema) builds a live Fabricator with a .fabricate() method.
  4. .fabricate() is the only place randomness actually happens.

See Mental model for why this three-layer split exists.

initialize() needs no configuration. It captures the wall-clock instant of the call as its clock, and that single number is both what makes every run different and what replays any one of them: log context.clock when something fails, pass it back as clock: new Date(logged), and you get that run's data again. See Reproducibility.

Overriding specific fields

Fabricate with everything random except a few fields you care about:

const item = Product.fabricate({ name: "Widget", inStock: true });

This uses the Fabricator's own already-drawn randomness for every other field — it's a per-call override, not a new schema. See Composition for the schema-level equivalent, .override(...).