Skip to the content
OrielDocs
0.1.0-alpha.10GitHub

Models

Eloquent: factories

A factory makes models with realistic attribute values, for your tests and your seeders: one model, or a hundred, with their related models.

Introduction#

Each factory is a class in database/factories that describes one model's default attributes. A new app has UserFactory:

database/factories/UserFactory.ts
import { Factory, Hash, fake } from '@orieljs/framework'import { User } from '../../app/Models/User'type Attributes = Record<string, unknown>/** The password every factory-made user has, hashed once. */let password: string | undefinedexport default class UserFactory extends Factory<User> {  model = User  definition() {    return {      name: fake().name(),      email: fake().unique().safeEmail(),      email_verified_at: new Date(),      password: 'password',      remember_token: fake().lexify('??????????'),    }  }  /** Indicate that the model's email address should be unverified. */  unverified() {    return this.state({ email_verified_at: null })  }  /** Hashes the default password (the model has no hashed cast). */  protected override async attributesFor(overrides: Attributes, index: number): Promise<Attributes> {    const attributes = await super.attributesFor(overrides, index)    if (attributes.password === 'password') attributes.password = password ??= await Hash.make('password')    return attributes  }}

model names the model, and definition() returns the attributes every model gets, unless you give others. fake() makes the values: names, email addresses, sentences, numbers and dates.

Factories set every attribute they are given, whatever the model's fillable says.

Defining model factories#

Generating factories#

make:factory writes a factory in database/factories, named after its model:

Terminal
node oriel make:factory PostFactory

Oriel finds the factories in database/factories by itself when your app runs through oriel, as a command or under oriel serve, and in your tests: every factory class a file there exports. An app started another way, such as with public/index.ts, registers its factories with Factory.register(), or User.factory() throws "No factory registered for [User].".

A model's factory() returns its factory. To have its own methods, such as unverified(), typed, declare it, as a new app's User does:

app/Models/User.ts
import { Model, type HasFactory } from '@orieljs/framework'import type UserFactory from '../../database/factories/UserFactory'export class User extends Model {  declare static factory: HasFactory<UserFactory>}

Factory states#

A state changes some attributes. Write it as a method that calls state():

class PostFactory extends Factory<Post> {  model = Post  definition() {    return { title: fake().sentence(), slug: fake().slug(), body: fake().paragraph() }  }  /** Indicate that the post is published. */  published() {    return this.state({ published_at: new Date() })  }}

state() also takes a function, which receives the attributes so far and the model's place in the batch:

const users = await User.factory(3)  .state((attributes, { index }) => ({ name: `User ${index + 1}` }))  .make()

"Trashed" state#

trashed() makes soft-deleted models, with a deleted_at date:

const post = await Post.factory().trashed().create()

Factory callbacks#

afterMaking() and afterCreating() run a function with each model made or created. Register them in the factory's configure():

class UserFactory extends Factory<User> {  model = User  definition() {    return { name: fake().name(), email: fake().unique().safeEmail() }  }  override configure() {    return this.afterMaking((user) => {      // ...    }).afterCreating((user) => {      // ...    })  }}

Creating models using factories#

Instantiating models#

make() makes models without saving them. With count(), or a number given to factory(), it makes a collection: a plain Collection, where Laravel's is an Eloquent collection, so modelKeys() and load() aren't on it:

const user = await User.factory().make()const users = await User.factory().count(3).make()const others = await User.factory(3).make()

Applying states#

const users = await User.factory().count(5).unverified().make()

Overriding attributes#

Give make() or create() the attributes to set:

const user = await User.factory().make({ name: 'Abigail Otwell' })

Persisting models#

create() makes the models and saves them:

const user = await User.factory().create()const users = await User.factory().count(3).create()

makeOne() and createOne() always return one model, typed as one. createMany() takes a number, or a list of attributes, one model each. raw() returns the attributes without making a model.

Sequences#

sequence() gives the models of a batch attributes in turn, starting again after the last:

const users = await User.factory().count(10).sequence({ name: 'Taylor' }, { name: 'Abigail' }).create()

Five users are named Taylor, and five Abigail.

Factory relationships#

Has many relationships#

has() creates related models with each model, through a relation of the model, named after the related model in the plural unless you name it:

const user = await User.factory().has(Post.factory().count(3)).create()const writer = await User.factory().has(Post.factory().count(3), 'posts').create()

Belongs to relationships#

for() sets the parent of the models it makes, a model you have or one its factory creates once for all of them:

const user = await User.factory().createOne()const posts = await Post.factory().count(3).for(user, 'author').create()

An attribute of a factory can also be another factory: the factory creates that model, and the attribute takes its key, as author_id: UserFactory.new() does in a post's definition.

Many to many relationships#

has() works on a many-to-many relation too, and its third argument gives the pivot table's extra columns:

const user = await User.factory().has(Role.factory().count(3), 'roles', { active: 1 }).create()

Polymorphic relationships#

has() creates the models of a morphMany() relation, and for() sets the owner of a morphTo() one.

The fake() helper#

fake() returns the generator factories use: a seedable subset of Faker's methods. unique() gives a value that the generator hasn't given before, and seed() makes the values repeat from one run to the next:

KindMethods
People and companiesfirstName(), lastName(), name(), userName(), email(), safeEmail(), company(), phoneNumber()
Textword(), words(), sentence(), sentences(), paragraph(), paragraphs(), text(), title(), slug(), url(), city(), country()
NumbersnumberBetween(), randomNumber(), randomFloat(), randomDigit(), random() (a number from 0 to 1), boolean(), uuid()
Patterns and datesnumerify('###'), lexify('???'), bothify('##??'), hexColor(), dateTime(), dateTimeBetween('-1 year', 'now'), date()

Privacy policy ·

esc