Factories are a useful way to seed your database, either during development or within tests. Whenever you generate an object via a factory, it will automatically get added to the database, and thus get an autoassigned id
.
You define factories by creating files under the /mirage/factories
directory. The name of the factory is determined by the filename.
Factories have attributes, and you create objects from factory definitions using the server.create
and server.createList
methods.
Attributes can be static (strings, numbers or booleans) or dynamic (a function). Here’s a factory with some static attributes:
// mirage/factories/user.js
import Mirage from 'ember-cli-mirage';
export default Mirage.Factory.extend({
name: 'Link',
age: 563,
evil: false,
});
Functions receive the sequence number i as an argument, which is useful to create dynamic attributes:
// mirage/factories/user.js
import Mirage from 'ember-cli-mirage';
export default Mirage.Factory.extend({
name: function(i) {
return 'User ' + i
}
});
The first user generated (per test) would have a name of User 0
, the second a name of User 1
, and so on.
Finally, you can also reference static attributes (numbers, strings or booleans) within your dynamic attributes via this
:
// mirage/factories/contact.js
import Mirage from 'ember-cli-mirage';
export default Mirage.Factory.extend({
age: 18,
is_admin: function(i) {
return this.age > 30;
}
});
You should define the attributes of your factory as the “base case” for your objects, and override them within your tests. We’ll discuss how do to this in the Creating Objects section.
The Faker.js library is included with Mirage, and its methods work nicely with factory definitions:
// app/mirage/factories/user.js
import Mirage, { faker } from 'ember-cli-mirage';
export default Mirage.Factory.extend({
firstName() { return faker.name.firstName(); },
lastName() { return faker.name.lastName(); },
avatar() { return faker.internet.avatar(); }
});
We’ve also added two methods on the faker
namespace, list.cycle
and list.random
, which are useful if you have a set of data you want your factories to iterate through:
// app/mirage/factories/subject.js
import Mirage, { faker } from 'ember-cli-mirage';
export default Mirage.Factory.extend({
name(i) {
return faker.list.cycle('Economics', 'Philosophy', 'English', 'History', 'Mathematics')(i);
},
students(i) {
return faker.list.random(100, 200, 300, 400, 500)(i);
}
});
cycle
loops through the data in order, while random
chooses a random element from the list each time an object is created.
View Faker’s docs for the full faker API.
You can also extend factories:
// mirage/factories/human.js
import Mirage from 'ember-cli-mirage';
export default Mirage.Factory.extend({
species: 'homo sapiens'
});
// mirage/factories/man.js
import Human from './human';
export default Human.extend({
gender: 'male'
});
Once you’ve defined a factory for a model, you can generate data for that model using server.create
and server.createList
, either from within /app/mirage/scenarios/default.js
for development, or from within your acceptance tests.
# server.create(type [, attrs])
Generates a single model of type type, inserts it into the database (giving it an id), and returns the data that was added.
test("I can view a contact's details", function() {
var contact = server.create('contact');
visit('/contacts/' + contact.id);
andThen(function() {
equal( find('h1').text(), 'The contact is Link');
});
});
You can override the attributes from the factory definition with a hash passed in as the second parameter. For example, if we had this factory
export default Mirage.Factory.extend({
name: 'Link'
});
we could override the name like this:
test("I can view the contacts", function() {
server.create('contact', { name: 'Zelda' });
visit('/');
andThen(function() {
equal( find('p').text(), 'Zelda' );
});
});
# server.createList(type, amount [, attrs])
Creates amount models of type type, optionally overriding the attributes from the factory with attrs.
Returns the array of records that were added to the database.
Here’s an example from a test:
test("I can view the contacts", function() {
server.createList('contact', 5);
var youngContacts = server.createList('contact', 5, { age: 15 });
visit('/');
andThen(function() {
equal(currentRouteName(), 'index');
equal( find('p').length, 10 );
});
});
And one from setting up your development database:
// app/mirage/scenarios/default.js
export default function(server) {
var contact = server.create('contact');
server.create('address', { contact_id: contact.id });
}