Notes on using Ember CLI Mirage

March 2, 2017

Almost every Ember app needs to communicate with an API and every Ember app needs tests (eh, right?). So what do you do when you have to make API calls in your Ember tests?

Ember CLI Mirage can solve this issue in an elegant way. I like to look at it as a mock node server that is primarily used for testing but can also be used by the actual ember app for demonstrating your app!

Negatives

Of course there are always try offs. Here are some issues I commonly see:

  • It’s hard to setup
  • It’s too much overhead
  • Have to maintain parity with my real API

These things can be true. My advice is that you should start small and incrementally add more as you need. After you set it up in a projects it’s easy to add to your tests.

Benefits

There are a lot of good reasons why you should use Migrate. Here are a couple:

  • Can be ran in CI
  • Dynamic endpoints allows for more in-depth acceptance tests
  • Could be used as a minimal server for validating ideas

Getting started

It’s relatively quick to get started also. Here are the basic steps:

  1. Install addon
  2. Do some configuration
  3. Setup endpoints
    3a. First with real stubs
    3b. Replace with fixtures
    3c. Create dynamic models using factories
  4. Run your tests!

Install addon

ember install ember-cli-mirage

Do some configuration

In environment.js set ENV['ember-cli-mirage'] to true for testing and false for everything else (unless you want to use it for different environments like development and production). More configurations at Mirage’s docs.

Begin with stubs

I recommend starting with stubs if you’re adding Mirage to an existing app that already has an API. You’ll thank yourself. In my opinion, it’s okay to start off with basic tests and drill down as you progress.

Lets say I have a todo list app and I want to test if I click on the checkbox to finish a task, that it goes away. If you already have a real API endpoint for getting the user’s latest tasks, this part is easy. I can just copy the payload from the request and stub out that request in Mirage.

You can do it by doing something like this:

this.get('/tasks', () => {
    return {
      "data": [
        {
          "id": "b3c21d7a-2843-47f1-89af-1ef1eb195966",
          "type": "task",
          "attributes": {
            "name": "Do Homework",
            "modified-time": "2016-09-21T17:09:39.566+00:00"
          }
        },
        {
          "id": "24cc0aca-2034-4d07-bf4b-ddda5d161416",
          "type": "task",
          "attributes": {
            "name": "Read book",
            "modified-time": "2016-09-20T17:32:09.697+00:00"
          }
        }
      ]
    }
});

So now when testing Ember will fetch from here. Simple enough right?

Well what if you need to create a task?

this.post('/tasks', (schema, request) => {
    return {
      "data": [
        {
          "id": "b41fe5e4-24ce-4e2c-8af4-8606dcecb025",
          "type": "task",
          "attributes": {
            "name": "New task!",
            "modified-time": "2016-09-22T10:02:09.016+00:00"
          }
        }
      ]
    }
});

This will only return one static task, which obviously isn’t ideal but it’s a place to start!

Stubbing out can be good to quickly get tests up and running but that most likely won’t help you cover most your app functionality.

Create dynamic models using factories

Time to replace /tasks with Factory Girl style factories. Here is where the real magic happens! Lets make it so that it dynamically creates new tasks so we can test better.

this.post('/tasks', (schema, request) => {
  const params = JSON.parse(request.requestBody);

  if (!params.name) {
    return new Mirage.Response(422, {some: 'header'}, {errors: {title: ['cannot be blank']}});
  } else {
    return schema.tasks.create(params);
  }
});

(Somewhat) Working example

Here is a Ember Twiddle (based off this Twiddle) that demonstrates the abilities of Ember Mirage. It has Mirage models (factories), serializer, endpoints, and also some tests. I highly recommend checking it out.

Skipping Mirage’s endpoint

Though code coverage isn’t perfect I recommend using it. ember-cli-code-coverage is a good option. You’ll have to allow a passthrough for it so that it doesn’t get caught by Mirage. You can do that by adding this in your config.js:

this.passthrough('/write-coverage');

Also you can namespace requests by adding this.namespace = '/api/v1'; in config.js

This is a very broad overview, there is so much more. Thank you for making a great library @samselikoff!

Ember CLI Mirage homepage

Tested against: Ember 2.10.0, Ember Mirage CLI 0.2.2