cult3

Mocking your JSON API with Ember CLI Mirage

Jul 06, 2015

Table of contents:

  1. Updating the Controller
  2. Creating an Ember Data model
  3. Hijacking the XHR Request with Ember CLI Mirage
  4. Creating the tasks endpoint
  5. Writing Fixtures
  6. Using Factories
  7. Using Ember Mirage in your Acceptance tests
  8. Conclusion

Last week we went from static HTML to calling a property on the controller to retrieve data for an Ember template.

We also created a very simple model object so that we could get the title attribute and display it on the page.

However, in the real world you would never hard code your data into the controller. The next step is to move towards getting data from a JSON API.

When writing automated tests, it’s important that you create an environment that allows your tests to run in isolation. This means you don’t want to actually hit a server to retrieve data because this introduces external dependencies.

So instead of hitting an external server, we need a way to mock the responses so we can run Acceptance Tests.

This allows us to set up the many different situations and scenarios that your application will find itself in.

In today’s tutorial we are going to look at setting up a mock server and returning data to the Acceptance Test.

Updating the Controller

The first thing we need to do is to remove the hard coded data from the Controller and instead query the Ember Data store. If you remember back to Finding, Creating and Saving records with Ember Data, you have access to the Ember Data store from your Controller and Routes:

import Ember from "ember";

export default Ember.Controller.extend({
  open: function () {
    return this.store.find("task", { status: "open" });
  }.property(),
});

This will make a GET request to /tasks?status=open. If you want to pass query parameters you can simply pass an object as the second parameter to the find() method.

Now if you run the tests again everything should be broken.

Creating an Ember Data model

Last week we created a standard Ember.Object to represent the Task model. In order to use Ember Data we need to extend DS.Model instead:

import DS from "ember-data";

export default DS.Model.extend({
  title: DS.attr("string"),
  status: DS.attr("string"),
});

To update the object simply copy and paste the above code into the task.js file under the models directory.

So far we only require two model properties. We will look at extending this model to include other stuff in future tutorials.

If you run the tests again they should still fail.

Hijacking the XHR Request with Ember CLI Mirage

The reason why the tests are failing is because Ember is attempting to request data from your API, however the API does not exist yet.

In order to make the tests pass we need to mock the API. Mocking the API is important because we don’t want to actually hit a live server during the test run.

There are a number of different ways in which you can mock XHR Requests in Javascript applications. Two of the most popular open source libraries are Pretender and Fauxjax.

However mocking your API whilst testing can also lead to difficulties.

An interesting Ember addon I recently stumbled across is Ember CLI Mirage. This package is built upon Pretender for hijacking the network requests, but also allows you to create fixtures and factories that make writing tests and setting up a development environment a lot easier.

This allows you to spend less time dealing with the headache of setting up your mocks and more time concentrating on your actual Ember application.

It also makes it much easier to set up very specific situations so you can ensure your application deals with things correctly.

And finally, Ember CLI Mirage also allows you to run your application in development without requiring a development API server. This means your client development can be totally isolated from the progress (or lack thereof) of your API.

To install Ember CLI Mirage, run the following command in Terminal:

ember install ember-cli-mirage

After the installation process has run you will have a new directory called mirage under app.

Creating the tasks endpoint

The first thing we need to do is to add the tasks endpoint to Ember Mirage’s config.js file.

If you open the config.js file you will see a big page of comments. These comments are documentation for how to set up your endpoints.

By default we could just write the following to mock the /api/tasks endpoint:

export default function () {
  this.get("/api/tasks");
}

However because we need to pass the status query parameter, we need to do something slightly more complicated:

export default function () {
  this.get("/api/tasks", function (db, request) {
    return { tasks: db.tasks.where(request.queryParams) };
  });
}

The second parameter to the get() method accepts a function that takes an instance of db and request.

The db allows you to query the database of fixtures that Ember Mirage will create for you on the fly.

The request is the current HTTP request.

So as you can see in the example above, I’m simply querying the db by passing the request.queryParams to the where() method.

I’m then returning an object of the results that will be the JSON response from the API.

Writing Fixtures

Ember Mirage is not only for your tests, it also allows you to work effectively in development without having to set up a development server to hit.

This is huge because you don’t want to slow the progress of your Client side development because you have to wait for your Server side development. Also, this makes your Client side code totally encapsulated meaning your can ship this project around without having to worry about connecting to a development server to get the data.

To return data whilst developing we need to create a Fixtures file. Create a new file called tasks.js under the fixtures directory in the mirage directory:

export default [
  {
    id: 1,
    title: "Task item 1",
    status: "open",
  },
  {
    id: 2,
    title: "Task item 2",
    status: "closed",
  },
  {
    id: 3,
    title: "Task item 3",
    status: "open",
  },
];

This is simply an array of objects that will be returned from the endpoint when making requests.

This means now that you should be able to fire up the application and see tasks 1 and 3 displayed on the page (because those are the only “open” ones).

Using Factories

When writing Acceptance tests, you don’t want to be using Fixtures because you are going to need to set up data for the different situations you want to test.

Instead you need a way to create responses on the fly.

Ember Mirage allows you to create Factories that can be used to set up any data you want to be returned for a particular test.

Create a new file called task.js under the factories directory of mirage:

import Mirage from "ember-cli-mirage";

export default Mirage.Factory.extend({
  title: function (i) {
    return "Task item " + i;
  },
  status: function (i) {
    return i % 2 === 0 ? "open" : "closed";
  },
});

The Factory is simply an object that extends the Mirage.Factory class.

For each property of the resource you can define what should be returned.

In my example above I’m using the id of the object and passing it into a function to create dynamic values.

The title property will be Task item n where n is the current id.

The status will be either open or closed depending on if the i is divisible by 2.

Using Ember Mirage in your Acceptance tests

Now that we have Ember Mirage set up we can start to use it in our Acceptance tests:

test("Count the number of tasks", function (assert) {
  server.createList("task", 3);

  visit("/");
  andThen(function () {
    var tasks = find(".task-list .task");
    assert.equal(tasks.length, 2);

    var task = find(".task-list .task:eq(0)");
    assert.equal(task.text(), "Task item 0");
  });
});

The only thing to note here is the following line:

server.createList("task", 3);

This is telling Ember Mirage to create 3 new Task objects. Ember Mirage will automatically hijack the request to the server and return this data.

The tests we wrote earlier should now pass.

Conclusion

Ember CLI Mirage is a pretty amazing addition to your Ember development toolset. You can now work on your Ember application without having to worry about the progress of your API.

This is beneficial for a number of reasons. Firstly, the two different sides of the application can be developed in parallel. As long as you agree on the interface of the API, everything should just work.

Secondly, you don’t need to run a local version of the API on your computer that is going to require setting up and updating.

And finally, it can allow you to build out your Ember application as a MVP. When it comes to writing the API you will already know exactly what you need.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.