Factory#
Type-safe data factories for generating test and seed data. Factories provide a clean, reusable way to create test data with sensible defaults and easy overrides.
Installation#
@faker-js/faker is an optional peer dependency for generating realistic fake data:
typescript
bun add -d @faker-js/fakerQuick Start#
typescript
bunx buntok make:factory userThe CLI creates a Prisma-oriented scaffold. Replace its placeholder definition with the fields required by your model before compiling it.
typescript
// src/factories/user.factory.ts
import { Factory } from "@buntok/core";
import { faker } from "@faker-js/faker";
import type { User } from "@prisma/client";
export const UserFactory = Factory.define<User>(() => ({
id: faker.number.int({ max: 10000 }),
name: faker.person.fullName(),
email: faker.internet.email(),
role: faker.helpers.arrayElement(["user", "admin"]),
}));Basic Usage#
typescript
import { UserFactory } from "@/factories/user.factory";
// Create one item
const user = await UserFactory.create();
// → { id: 1234, name: "John Doe", email: "john@example.com", role: "user" }
// Create many items
const users = await UserFactory.createMany(10);
// → array of 10 users
// Override fields per-call
const admin = await UserFactory.create({ role: "admin" });
// → { id: 5678, name: "Jane Smith", email: "jane@example.com", role: "admin" }Sync Build#
Use build() for synchronous generation without the afterCreate hook:
typescript
// Synchronous (no afterCreate hook)
const user = UserFactory.build({ name: "John" });
const users = UserFactory.buildMany(5);Default Overrides#
Set defaults that apply to all created items:
typescript
const UserFactory = Factory.define<User>(() => ({
id: faker.number.int({ max: 10000 }),
name: faker.person.fullName(),
email: faker.internet.email(),
role: faker.helpers.arrayElement(["user", "admin"]),
})).withDefaults({ role: "user" });
// All created items will have role: "user" unless overridden
const user = await UserFactory.create(); // role: "user"
const admin = await UserFactory.create({ role: "admin" }); // role: "admin"After Create Hook#
Run custom logic after each item is created (useful for database inserts, audit logs, etc.):
typescript
const UserFactory = Factory.define<User>(() => ({
id: faker.number.int({ max: 10000 }),
name: faker.person.fullName(),
email: faker.internet.email(),
role: faker.helpers.arrayElement(["user", "admin"]),
})).afterCreate(async (user) => {
await db.auditLog.create({
data: { userId: user.id, action: "created" }
});
});Relations#
Use Factory.ref() for lazy references to other factories:
typescript
const UserFactory = Factory.define<User>(() => ({
id: faker.number.int(),
name: faker.person.fullName(),
}));
const PostFactory = Factory.define(() => ({
id: faker.number.int(),
title: faker.lorem.sentence(),
userId: Factory.ref(() => UserFactory.build().id),
}));
// Each post gets a fresh user ID
const posts = await PostFactory.createMany(5);Random Pick#
typescript
// Pick one random item
const status = Factory.pick(["draft", "published", "archived"]);
// → "published"
// Pick multiple random items
const tags = Factory.pick(["typescript", "bun", "api", "testing"], 2);
// → ["api", "typescript"]Using with Seeders#
Generate seeders that use factories with the --factory flag:
typescript
bunx buntok make:seeder user --factorytypescript
// src/db/seeders/user.seeder.ts
import { prisma } from "@/lib/prisma";
import { UserFactory } from "@/factories/user.factory";
export async function seedUser() {
console.log("Seeding User...");
const items = UserFactory.buildMany(100);
await prisma.user.createMany({ data: items });
console.log("✓ User seeded successfully (100 records)");
}API Reference#
| Method | Description |
|---|---|
Factory.define<T>(fn) | Create a new factory with type T |
.create(overrides?) | Create one item (async, runs afterCreate) |
.createMany(count, overrides?) | Create multiple items |
.build(overrides?) | Generate one item synchronously (no afterCreate) |
.buildMany(count, overrides?) | Generate multiple items synchronously |
.withDefaults(defaults) | Set default overrides for all created items |
.afterCreate(callback) | Register post-creation hook (async supported) |
Factory.ref(fn) | Lazy reference for relations |
Factory.pick(arr, count?) | Random item(s) from array |
Info
Factories are designed for test and seed data generation. For production data, use your ORM's create methods directly.