/rosie

factory for building JavaScript objects, mostly useful for setting up test data. Inspired by factory_girl

Primary LanguageJavaScriptOtherNOASSERTION

Rosie

Build Status

Rosie the Riveter

Rosie is a factory for building JavaScript objects, mostly useful for setting up test data. It is inspired by factory_girl.

Usage

Define your factory, giving it a name and optionally a constructor function (Game in this example):

Factory.define('game'/*, Game*/)
  .sequence('id')
  .attr('is_over', false)
  .attr('created_at', function() { return new Date(); })
  .attr('random_seed', function() { return Math.random(); })

  // Default to two players. If players were given, fill in
  // whatever attributes might be missing.
  .attr('players', ['players'], function(players) {
    if (!players) { players = [{}, {}]; }
    return players.map(function(data) {
      return Factory.attributes('player', data);
    });
  });

Factory.define('player')
  .sequence('id')
  .sequence('name', function(i) { return 'player' + i; })

  // Define `position` to depend on `id`.
  .attr('position', ['id'], function(id) {
    var positions = ['pitcher', '1st base', '2nd base', '3rd base'];
    return positions[id % positions.length];
  });

Factory.define('disabled-player').extend('player').attr('state', 'disabled')

Now you can build an object, passing in attributes that you want to override:

var game = Factory.build('game', {is_over:true});

Which returns an object that looks roughly like:

{
    id:           1,
    is_over:      true,   // overriden when building
    created_at:   Fri Apr 15 2011 12:02:25 GMT-0400 (EDT),
    random_seed:  0.8999513240996748,
    players: [
                {id: 1, name:'Player 1'},
                {id: 2, name:'Player 2'}
    ]
}

For a factory with a constructor, if you want just the attributes:

Factory.attributes('game') // return just the attributes

You can also define a callback function to be run after building an object:

Factory.define('coach')
  .option('buildPlayer', false)
  .sequence('id')
  .attr('players', ['id', 'buildPlayer'], function(id, buildPlayer) {
    if (buildPlayer) {
      return [Factory.build('player', {coach_id: id})];
    }
  })
  .after(function(coach, options) {
    if (options.buildPlayer) {
      console.log('built player:', coach.players[0]);
    }
  });

Factory.build('coach', {}, {buildPlayer: true});

Node.js

To use Rosie in node, you'll need to require it first:

var Factory = require('rosie').Factory;

You might also choose to use unregistered factories, as it fits better with node's module pattern:

// factories/game.js
var Factory = require('rosie').Factory;

module.exports = new Factory()
  .sequence('id')
  .attr('is_over', false)
  // etc

To use the unregistered Game factory defined above:

var Game = require('./factories/game');

var game = Game.build({is_over: true});

ES6

Unregistered factories are even more natural in ES6:

// factories/game.js
import { Factory } from 'rosie';

export default new Factory()
  .sequence('id')
  .attr('is_over', false)
  // etc
  
// index.js
import Game from './factories/game');

const game = Game.build({is_over: true});

A tool like babel is currently required to use this syntax.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Install the test dependencies (script/bootstrap - requires NodeJS and npm)
  4. Make your changes and make sure the tests pass (npm test)
  5. Commit your changes (git commit -am 'Added some feature')
  6. Push to the branch (git push origin my-new-feature)
  7. Create new Pull Request

Credits

Thanks to Daniel Morrison for the name and Jon Hoyt for inspiration and brainstorming the idea.