Factory Basics
Understanding the core Factory class and its methods.
Factory Lifecycle
- Define - Create factory with generation function
- Configure - Add hooks, options, adapters
- Generate - Build single objects or batches
Core Methods
build() and buildAsync()
Generate single objects:
// Synchronous
const user = userFactory.build();
const customUser = userFactory.build({ name: 'John' });
// Asynchronous (for async factory functions or hooks)
const user = await userFactory.buildAsync();
batch() and batchAsync()
Generate multiple objects:
// Simple batch
const users = userFactory.batch(10);
// With overrides
const admins = userFactory.batch(5, { isAdmin: true });
// Cycling overrides
const mixedUsers = userFactory.batch(6, [
{ role: 'admin' },
{ role: 'user' },
{ role: 'guest' },
]);
use()
Update factory definition:
// Original factory
const factory = new Factory<User>(factoryFn);
// Update definition
factory.use((faker) => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
isAdmin: faker.datatype.boolean(0.3), // Now 30% admins
}));
extend()
Add properties to existing factory:
const adminFactory = userFactory.extend({
role: 'admin',
permissions: ['read', 'write', 'delete'],
});
Hooks
Transform data before and after generation:
const factory = new Factory<User>(factoryFn)
.beforeBuild((data) => {
// Normalize email
if (data.email) {
data.email = data.email.toLowerCase();
}
return data;
})
.afterBuild((user) => {
// Add computed field
user.displayName = `${user.name} (${user.email})`;
return user;
});
Factory Options
Configure factory behavior:
const factory = new Factory<User>(factoryFn, {
maxDepth: 5, // Depth limiting
locale: 'en', // Faker locale
fixtures: {
// Fixture configuration
basePath: './fixtures',
validateSignature: true,
},
});
Advanced Patterns
Lazy References
import { Ref } from 'interface-forge';
const userRef = new Ref<User>();
const postFactory = new Factory<Post>((faker) => ({
id: faker.string.uuid(),
title: faker.lorem.sentence(),
author: userRef.get(), // Lazy reference
}));
// Set reference later
userRef.set(userFactory.build());
Context-Aware Generation
Factory functions can access override values through the optional kwargs
parameter, enabling context-aware data generation:
const userFactory = new Factory<User>((faker, iteration, kwargs) => {
// Use provided age or generate one
const age = kwargs?.age ?? faker.number.int({ min: 18, max: 80 });
return {
id: kwargs?.id ?? faker.string.uuid(),
name: kwargs?.name ?? faker.person.fullName(),
age,
// Context-aware: underAge depends on the actual age used
underAge: age < 18,
// Conditional generation based on age
driversLicense: age >= 16 ? faker.string.alphanumeric(8) : null,
};
});
// Generates consistent data
const minor = userFactory.build({ age: 16 });
// { age: 16, underAge: true, driversLicense: null, ... }
const adult = userFactory.build({ age: 25 });
// { age: 25, underAge: false, driversLicense: "A1B2C3D4", ... }
Conditional Generation
const profileFactory = new Factory<Profile>((faker) => {
const type = faker.helpers.arrayElement(['basic', 'premium']);
return {
id: faker.string.uuid(),
type,
features:
type === 'premium'
? ['unlimited', 'priority-support']
: ['basic', 'email-support'],
maxStorage: type === 'premium' ? 1000 : 100,
};
});
State Management
class UserFactory extends Factory<User> {
private nextId = 1;
constructor() {
super((faker) => ({
id: (this.nextId++).toString(),
name: faker.person.fullName(),
email: faker.internet.email(),
}));
}
buildAdmin() {
return this.build({ role: 'admin' });
}
buildGuest() {
return this.build({ role: 'guest' });
}
}