npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@robinvdbroeck/factory-girl

v6.0.1

Published

A factory library for Node.js and JavaScript inspired by factory_girl

Readme

factory-girl

factory-girl is a factory library for Node.js inspired by Factory_girl. It works asynchronously and supports associations and the use of functions for generating attributes.

Installation

npm install @robinvdbroeck/factory-girl

Requires Node.js >= 22.12.

Usage

Refer to the tutorial for a gentle introduction of building a simple user factory.

Here's the crash course:

import { factory } from '@robinvdbroeck/factory-girl';
import User from '../models/user';

factory.define('user', User, {
  username: 'Bob',
  score: 50
});

factory.build('user').then((user) => {
  console.log(user); // => User {username: 'Bob', score: 50}
});

Defining Factories

Define factories using the factory.define() method.

For example:

// Using objects as initializer
factory.define('product', Product, {
  // use sequences to generate values sequentially
  id: factory.sequence('Product.id', (n) => `product_${n}`),
  // use functions to compute some complex value
  launchDate: () => new Date(),
  // return a promise to populate data asynchronously
  asyncData: () => fetch('some/resource')
});
factory.define('user', User, {
  // seq is an alias for sequence
  email: factory.seq('User.email', (n) => `user${n}@ymail.com`),

  // use the chance(http://chancejs.com/) library to generate real-life like data
  about: factory.chance('sentence'),

  // use assoc to associate with other models
  profileImage: factory.assoc('profile_image', '_id'),

  // or assocMany to associate multiple models
  addresses: factory.assocMany('address', 2, '_id'),

  // use assocAttrs to embed models that are not persisted
  creditCardNumber: factory.assocAttrs('credit_card', 'number', { type: 'masterCard' }),

  // use assocAttrs or assocAttrsMany to embed plain json objects
  twitterDetails: factory.assocAttrs('twitter_details')
});
// Using functions as initializer
factory.define('account', Account, (buildOptions) => {
  let attrs = {
    confirmed: false,
    confirmedAt: null
  };

  // use build options to modify the returned object
  if (buildOptions.confirmedUser) {
    attrs.confirmed = true;
    attrs.confirmedAt = new Date();
  }
  return attrs;
});

// buildOptions can be passed while requesting an object
factory.build('account', {}, { confirmed: true });

Options

Options can be provided when you define a factory:

factory.define('user', User, { foo: 'bar' }, options);

Alternatively you can set options for the factory that will get applied for all model-factories:

factory.withOptions(options);

Currently the supported options are:

afterBuild: function(model, attrs, buildOptions)

Provides a function that is called after the model is built. The function should return the instance or a Promise for the instance.

afterCreate: function(model, attrs, buildOptions)

Provides a function that is called after a new model instance is saved. The function should return the instance or throw an error. For asynchronous functions, it should return a promise that resolves with the instance or rejects with the error.

factory.define(
  'user',
  User,
  { foo: 'bar' },
  {
    afterBuild: (model, attrs, buildOptions) => {
      return doSomethingAsync(model).then(() => {
        doWhateverElse(model);
        return model;
      });
    },
    afterCreate: (model, attrs, buildOptions) => {
      modify(model);
      if ('something' === 'wrong') {
        throw new Error();
      }
      maybeLog('something');
      return model;
    }
  }
);

Extending Factories

You can extend a factory using #extend:

factory.define('user', User, { username: 'Bob', expired: false });
factory.extend('user', 'expiredUser', { expired: true });
factory.build('expiredUser').then((user) => {
  console.log(user); // => User { username: 'Bob', expired: true });
});

#extend(parent, name, initializer, options = {})

The #extend method takes the same options as #define except you can provide a different Model using options.model.

Using Factories

Factory#attrs

Generates and returns model attributes as an object hash instead of the model instance. This may be useful where you need a JSON representation of the model e.g. mocking an API response.

factory.attrs('post').then((postAttrs) => {
  // postAttrs is a json representation of the Post model
});

factory.attrs('post', { title: 'Foo', content: 'Bar' }).then((postAttrs) => {
  // builds post json object and overrides title and content
});

factory.attrs('post', { title: 'Foo' }, { hasComments: true }).then((postAttrs) => {
  // builds post json object
  // overrides title
  // invokes the initializer function with buildOptions of {hasComments: true}
});

You can use Factory#attrsMany to generate a set of model attributes

factory.attrsMany('post', 5, [{ title: 'foo1' }, { title: 'foo2' }]).then((postAttrsArray) => {
  // postAttrsArray is an array of 5 post json objects
  debug(postAttrsArray);
});

Factory#build

Builds a new model instance that is not persisted.

factory.build('post').then((post) => {
  // post is a Post instance that is not persisted
});

The buildMany version builds an array of model instances.

factory.buildMany('post', 5).then((postsArray) => {
  // postsArray is an array of 5 Post instances
});

Similar to Factory#attrs, you can pass attributes to override or buildOptions.

Factory#create(name, attrs, buildOptions)

Builds a new model instance that is persisted.

factory.create('post').then((post) => {
  // post is a saved Post instance
});

Factory#createMany(name, num, attrs, buildOptions = {})

The createMany version creates an array of model instances.

factory.createMany('post', 5).then((postsArray) => {
  // postsArray is an array of 5 Post saved instances
});

Similar to Factory#attrs and Factory#build, you can pass attrs to override and buildOptions. If you pass an array of attrs then each element of the array will be used as the attrs for a each model created.

Factory#createMany(name, attrs, buildOptions = {})

If you can pass an array of attrs then you can omit num and the length of the array will be used.

Factory#cleanUp

Destroys all of the created models. This is done using the adapter's destroy method. It might be useful to clear all created models before each test or testSuite.

Adapters

Adapters handle model construction, persistence, and destruction. An adapter can be registered as the default (used for all models) or scoped to specific factory names.

import { factory, DefaultAdapter } from '@robinvdbroeck/factory-girl';

// set as the default adapter
factory.setAdapter(new DefaultAdapter());

// or only for one model-factory
factory.setAdapter(new DefaultAdapter(), 'factory-name');

Custom Adapters

You can write a custom adapter to integrate with any ORM. An adapter is a plain class implementing five methods:

| Method | Signature | Description | | --------- | ----------------------- | ------------------------------------------------------------- | | build | (Model, props) | Construct a new (unsaved) model instance | | save | (model, Model) | Persist the instance, return a Promise resolving to the model | | destroy | (model, Model) | Delete the instance, return a Promise | | get | (model, attr, Model) | Read a single attribute from the instance | | set | (props, model, Model) | Write attributes onto the instance |

Example adapter for a Sequelize-style ORM where Model.build(props) constructs instances and attribute access is via plain properties:

class SequelizeAdapter {
  build(Model, props) {
    return Model.build(props);
  }
  async save(model) {
    return model.save();
  }
  async destroy(model) {
    return model.destroy();
  }
  get(model, attr) {
    return model[attr];
  }
  set(props, model) {
    return model.set(props);
  }
}

factory.setAdapter(new SequelizeAdapter());

DefaultAdapter

DefaultAdapter is the built-in adapter. It expects your model class to follow this interface:

  • new Model(props) — constructor receives the attributes object
  • model.save() — persists the instance, may return a Promise
  • model.destroy() — deletes the instance, may return a Promise
  • model.get(attr) — returns the value of an attribute
  • model.set(props) — sets attributes on the instance
import { factory, DefaultAdapter } from '@robinvdbroeck/factory-girl';

class User {
  constructor(attrs) {
    Object.assign(this, attrs);
  }
  save() {
    // persist the model, return a Promise if async
  }
  destroy() {
    // delete the model, return a Promise if async
  }
  get(attr) {
    return this[attr];
  }
  set(props) {
    Object.assign(this, props);
  }
}

factory.setAdapter(new DefaultAdapter());
factory.define('user', User, { username: 'Bob' });

Creating new Factories

You can create multiple independent factory instances with different settings:

import { factory } from '@robinvdbroeck/factory-girl';

const anotherFactory = new factory.FactoryGirl();
anotherFactory.setAdapter(new DefaultAdapter());

History

This module started out as a fork of factory-lady, but the fork deviated quite a bit. Version 4.0 was a complete rewrite with thanks to @chetanism.

License

Copyright (c) 2016 Chetan Verma.
Copyright (c) 2014 Simon Wade. Copyright (c) 2011 Peter Jihoon Kim.

This software is licensed under the MIT License.