@nestbolt/factory
Defining Factories
Create factory classes with entity definitions, state methods, and lifecycle hooks.
Factories are classes that define how to generate fake data for a specific TypeORM entity. Each factory extends BaseFactory<T> and provides a definition() method that returns default attributes.
Basic Factory
A minimal factory requires two things: an entity getter and a definition() method:
import { BaseFactory } from "@nestbolt/factory";
import type { Faker } from "@faker-js/faker";
import { User } from "../entities/user.entity";
export class UserFactory extends BaseFactory<User> {
get entity() {
return User;
}
definition(faker: Faker): Partial<User> {
return {
name: faker.person.fullName(),
email: faker.internet.email(),
role: "user",
age: faker.number.int({ min: 18, max: 65 }),
active: true,
};
}
}entity
The entity getter returns the TypeORM entity class constructor. This is used to instantiate new entities and to resolve the TypeORM repository when persisting.
definition(faker)
The definition() method receives a Faker instance and returns a Partial<T> with default attribute values. This method is called once per entity generated.
You can use any Faker method to generate realistic data:
definition(faker: Faker): Partial<Post> {
return {
title: faker.lorem.sentence(),
body: faker.lorem.paragraphs(3),
status: faker.helpers.arrayElement(["draft", "published"]),
viewCount: faker.number.int({ min: 0, max: 10000 }),
publishedAt: faker.date.past(),
};
}State Methods
State methods define named variations of your factory. Any method on your factory class that returns a Partial<T> can be used as a named state:
export class UserFactory extends BaseFactory<User> {
get entity() { return User; }
definition(faker: Faker): Partial<User> {
return {
name: faker.person.fullName(),
email: faker.internet.email(),
role: "user",
active: true,
};
}
admin(): Partial<User> {
return { role: "admin" };
}
inactive(): Partial<User> {
return { active: false };
}
withAge(age: number): Partial<User> {
return { age };
}
}States are applied via the builder's .state() method:
await factoryService.use(UserFactory).state("admin").create();
await factoryService.use(UserFactory).state("admin").state("inactive").create();See States for more details on using states.
Lifecycle Hooks
Factories support two optional lifecycle hooks that run after an entity is generated:
afterMake
Called after an entity is instantiated but not yet persisted. Runs for both make() and create() calls:
export class UserFactory extends BaseFactory<User> {
get entity() { return User; }
definition(faker: Faker): Partial<User> {
return {
name: faker.person.fullName(),
email: faker.internet.email(),
};
}
async afterMake(entity: User, faker: Faker): Promise<void> {
// Normalize email to lowercase
entity.email = entity.email.toLowerCase();
}
}afterCreate
Called after an entity is persisted to the database. Only runs for create() and createMany() calls:
export class PostFactory extends BaseFactory<Post> {
get entity() { return Post; }
definition(faker: Faker): Partial<Post> {
return {
title: faker.lorem.sentence(),
body: faker.lorem.paragraphs(2),
status: "draft",
};
}
async afterCreate(entity: Post, faker: Faker): Promise<void> {
// Log or perform side effects after persistence
console.log(`Created post #${entity.id}: ${entity.title}`);
}
}Hook Execution Order
When calling create(), hooks execute in this order:
definition()generates base attributes- States, sequences, and overrides are applied
- Entity is instantiated
- Factory
afterMakeruns (if defined) - Builder
afterMakingcallbacks run (if any) - Entity is persisted to the database
- Factory
afterCreateruns (if defined) - Builder
afterCreatingcallbacks run (if any)
When calling make(), only steps 1--5 execute.
Factory Organization
A recommended project structure for factories:
src/
factories/
user.factory.ts
post.factory.ts
comment.factory.ts
seeders/
database.seeder.ts
entities/
user.entity.ts
post.entity.ts
comment.entity.tsRegistration
All factories must be registered in FactoryModule.forRoot() before they can be used:
FactoryModule.forRoot({
factories: [UserFactory, PostFactory, CommentFactory],
});Using an unregistered factory throws a FactoryNotRegisteredException:
// This throws if CommentFactory is not in the factories array
factoryService.use(CommentFactory);