Once you’ve defined your server’s routes, you’ll probably want to seed your database with some initial data. You can use factories or fixtures, or both.
In general Mirage recommends that you use factories, for a few reasons:
First, we’ll look at using factories.
If you’ve never used factories before, think of them as a way to make database records. You define factories by creating files under the /mirage/factories
directory. The name of the factory, which you reference in your tests, is determined by the filename.
Factories have attributes which can be strings, numbers, booleans or functions:
// mirage/factories/user.js
import Mirage from 'ember-cli-mirage';
export default Mirage.Factory.extend({
name(i) { return `User ${i}`; },
age: 20,
admin: false
});
Functions take one parameter, the sequence number of the object being created. This lets you create records with dynamic attributes.
Each time this factory is used to create an object, it will have an autogenerated id
assigned to it, since it will be inserted into the database. So, the objects created from the example factory above will look like
{ id: 0, name: "User 0", age: 20, admin: false }
{ id: 1, name: "User 1", age: 20, admin: false }
{ id: 2, name: "User 2", age: 20, admin: false }
and so on.
Mirage also includes the Faker.js library, which pairs nicely with your factories to make your mock data more realistic:
// 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(); },
age() { return faker.list.random(18, 20, 28, 32, 45, 60); }, // .list method added by Mirage
});
Once you’ve defined your factories, you can use them to seed your database via the server.create
and server.createList
methods.
To seed your database in development, create the file /app/mirage/scenarios/default.js
, and export a function that takes a single argument, server
, your Mirage server’s instance. This function will run when Mirage is initialized during development.
A simple scenario may look like this:
// app/mirage/scenarios/default.js
export default function(server) {
server.createList('post', 10);
var user = server.create('user', { name: 'Zelda' });
server.createList('comment', 20, { user_id: user.id });
}
Currently, only the default scenario is supported, though there are plans to support switching between multiple scenarios in development.
Note that this scenario will be ignored during testing. This is so you can change your development data without affecting your tests.
During acceptance testing, Mirage’s initializer is run when your Ember app starts up, and server
is available in each test.
Mirage starts each test with a clean database. Use create
and createList
to define your data on a per-test basis:
test('I can view the users', function() {
server.createList('user', 3);
visit('/contacts');
andThen(function() {
equal( find('p').length, 3 );
});
});
Learn more about acceptance testing in the next section.
You can also use server.loadFixtures
to load fixture files in your default scenario or tests, meaning you can simultaneously leverage fixtures and factories. See the guide for more info.
You can also create related data with factories. Until this PR lands, you’ll need to manage the foreign keys yourself, which you’ll do by overriding your factories’ default attributes. Here’s an example:
var user = server.create('user');
server.createList('post', 10, { user_id: user.id });
Notice that create
and createList
return the database records that were created by the factory, so you can use the user’s id
to relate the posts back to that user. Now that the foreign keys are set up, you can use the shorthand routes to sideload the user’s related data:
this.get('/users/:id', ['user', 'posts']);
or interact with the data directly via db.posts.where({ user_id: user.id })
, for example.
You can also choose to use fixtures instead of (or in addition to) factories. If you’ve never used fixtures before, think of a fixture file as a database table. To add data to your users
table, for instance, create the file /app/mirage/fixtures/users.js
:
// app/mirage/fixtures/users.js
export default [
{ id: 1, name: 'Link' },
{ id: 2, name: 'Zelda' },
{ id: 3, name: 'Epona' }
];
Fixture filenames are always plural, and export arrays of POJOs. During development, this data will be added to Mirage’s database and will be available in route handlers via db.users
. Be sure to delete the /mirage/scenarios
directory in order for your fixtures to load during development.
Some people use fixtures during development but choose to use factories in their tests. If you want your fixture files to also load during testing, simply delete the /mirage/factories
directory.
To create related data, you’ll need to manage the foreign keys yourself. Let’s look at an example.
Suppose a user
has many addresses
. Your fixture data may look like this:
// app/mirage/fixtures/users.js
export default [
{ id: 1, name: 'Link' },
{ id: 2, name: 'Zelda' }
];
// app/mirage/fixtures/addresses.js
export default [
{ id: 1, name: '123 Hyrule Way', user_id: 1 },
{ id: 2, name: '11 Kokiri Forest St.', user_id: 1 },
{ id: 3, name: '5 Lost Woods Dr.', user_id: 2 }
];
Now you can use the shorthand this.get('/users/:id', ['user', 'addresses']
, and Mirage will return the user whose id matches the :id
route param, along with this user’s related addresses - i.e., addresses whose user_id
matches the param.