Skip to content

Instantly share code, notes, and snippets.

@chrisjensen
Last active December 5, 2019 20:08
Show Gist options
  • Save chrisjensen/d68351424314319328967e92faee9095 to your computer and use it in GitHub Desktop.
Save chrisjensen/d68351424314319328967e92faee9095 to your computer and use it in GitHub Desktop.
How to create singleton associations in FactoryGirl
/**
* For use with https://github.com/aexmachina/factory-girl
*
* Helper for defining an association to a record that should only be instantiated once.
* Uses sequelizes findOrCreate() to ensure the record is created on
* first invocation, and reused subsequently
*
* NOTE: Make sure to use this within a function initialiser or the singleton
* record will be created when factories are defined which may cause confusion
*
* NOTE: Make sure uniqueAttr is the name of a column that has a unique constraint
* or it's highly likley you will end up with duplicate records in your db.
*
* @param {String} factory Name of the factory to use
* @param {String} uniqueAttr A unique attribute to use to check if the record
* has already been created
* @param {String} attr Attribute to return (otherwise returns the record)
* @returns {Model|Object} Returns either the record itself or the value of record[attr]
*/
async function singleton(factory, uniqueAttr, attr) {
// Find the default campaign
if (!this.factories[factory]) {
throw new Error(`Unknown factory: ${factory}`);
}
const model = this.factories[factory].Model;
const defaults = await this.attrs(factory);
const where = {};
where[uniqueAttr] = defaults[uniqueAttr];
const record = await model.findOrCreate({ where, defaults });
return attr ? record[0][attr] : record[0];
}
module.exports = singleton;
const fg = require('factory-girl').factory;
const singletonFactory = require('./mixins/singletonFactory');
const FactoryGirl = fg.FactoryGirl;
const factory = new FactoryGirl();
factory.singleton = singletonFactory;
factory.define('defaultOrganisation', Organisation, {
name: 'ACME Inc',
slug: 'acme.com',
});
// NOTE: The initialiser must be a function
factory.define('department', Department, () => ({
name: factory.sequence('Department.name', n => `department ${n}`),
organisationId: factory.singleton('defaultOrganisation', 'slug', 'id'),
}));
async function test() {
const department1 = await factory.create('department');
const department2 = await factory.create('department');
assertEqual(department1.organisationId, department2.organisationId);
}
test();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment