factory-castrado

Node.js library for generating test data with factories. Inspired by factory_girl


Keywords
factory, test, testing, data, bdd, tdd, fixture, mock, mocking
License
WTFPL
Install
npm install factory-castrado@0.0.12

Documentation

factory-castrado

Build Status

Factory Castrado is a library for Node.js which provides factories for objects creation. It is designed for use with Backbone-style models which use new Model(attributes) for initialization and model.create(function(err, model){...}) for saving.

It is highly inspired by:

Installation

Node.js:

npm install factory-castrado

Usage

Model requirements

Coffeescript:

# factory-castrado puts only one requirement on models: 
# they *must be constructor functions* that accept an attributes object.
# Your model must be comply with:
model = new Model(attributes)

# In order to save to model to a database during Factory.create, 
# factory-castrado uses "model.create (err, model) ->"
Model::create = (done) ->
	# ...Insert into db...
	done(error, this)

# If no create method is found, the model is passed back without saving.

# If a non-backbone object is given for a factory's models,
# the model.get() and model.set() methods are shimmed.

Defining factories

Coffeescript:

Factory		= require 'factory-castrado'
Model		= require('backbone').Model
PlainModel	= class extends Object # Bare object

counter = 1

# Define with (name, model, attributes)
Factory.define 'user', Model,
	email: (cb) -> cb("user#{counter++}@test.com")
	name: "Test name"
	password: 'abc123'

# With associations, using (name, options):
Factory.define 'post',
	model: Model
	attributes:
		title: "Test title"
		content: "Test content"
	associations:
		user:				# This creates an embedded post.user object, and a user_id attribute
			factory: 'user'	# Defaults to association name (user here)
			key: 'user_id'	# Defaults to name + _id

# Non-Backbone objects work the same:
# NOTE: factory-castrado shims model.get() and model.set() methods
Factory.define 'session', PlainModel,
	id: (cb) -> cb(Math.random())
	expires: (cb) -> cb (require 'moment')().add('days', 7).toDate()

Factory.define 'plainUser',
	model: PlainModel,
	attributes:
		name: "Test"
	associations:
		session:				
			factory: 'session'	# Attaches embedded user.session
			key: 'session_id'	# Attaches user.session_id foreign key

			# On a backbone-style model, the foreign key would be in 
			# the model's attributes hash, accessed using user.get('session_id')

Using factories

Coffeescript:

Factory.build 'user', (user) -> # (err, user) -> Also supported
	# user is an unsaved user model

Factory.build 'user', name:"New", (user) ->
	# user is an unsaved user model with name "New"

Factory.build 'post', (post) ->
	# post is an unsaved post model
	# post.user is a saved associated user model
	# post has new attribute 'user_id' with the user's id

Factory.create 'user', (user) -> # (err, user) -> Also supported
	# User is SAVED model

# A note about Error-first callbacks:
# factory-castrado checks the callback's arity to determine
# if it is an error-first callback. These are both supported:
Factory.create 'user', (err, user) ->
Factory.create 'user', (user) -> # Don't care about the error

# However, this will NOT work:
Factory.create 'user', (err) -> # DOES NOT WORK - argument will be user, not err.

Associations

Coffeescript:

Factory.define 'post',
	model: Model
	associations:
		user:
			# Defaults to association name (user here)
			factory: 'user'

			# Defaults to name + _id
			key: 'user_id'

			# Gets foreign key from associated model
			# Default getter, just grabs id
			getter: (assocObj) -> return assocObj.id

			# Sets foreign key on factory's built model
			# Default setter (pseudocode - uses 'key' from above if setter not overridden)
			setter: (obj, val) -> obj.set {{key}}, val

			 # Conveniently provides default setters/getters
			type: 'id' # Currently supported: "id", "ids[]"
			# Using type: "ids[]" provides a default setter than inserts id into object's array of ids


# Id-array associations
# This will generate a message model with:
# user_ids: [id1, id2]
# as well as user models attached directly at msg.to , msg.from
Factory.define 'message',
	model: MessageModel
	attributes:
		title: "Hello World"
	associations:
		from:
			factory: 'user'
			key: 'user_ids'
			type: 'ids[]'
		to:
			factory: 'user'
			key: 'user_ids'
			type: 'ids[]'

Custom Factories

Coffeescript:

# Custom factories can be defined with a function
Factory.define 'two users and a random number', (callback) ->
	Factory.create 'user', (user1) ->
		Factory.create 'user', (user2) ->

			randomNum = ~~(Math.random()*10)
			callback(user1, user2, randomNum)

# Using it:
Factory.create 'two users and a random number', (user1, user2, randomNum) ->

# Custom attributes will be passed through to
# custom factories after callback parameter:
Factory.define 'helloworld', (callback, options) ->
	data = "Hello World"
	if options?.caps
		return callback(data.toUpperCase())

	callback(data)

Factory.create 'helloworld', (string) -> # string == 'Hello World'
Factory.create 'helloworld', caps:true, (string) -> # string == 'HELLO WORLD'

Getting attributes with attributesFor

Coffeescript:

# Get raw object of attributes
Factory.attributesFor 'user', (attrs) ->

# Specify some options
Factory.attributesFor 'user', name: "Bob", (attrs) ->

License

WTFPL v2