We are going to write a few simple acceptance tests today. I've set up a basic ember app that displays a list of events and allows the user to click on an event and view the details of that event. For this app, there are two models: an Event model and an Address model. They have a one-to-one relationship. With regard to routes, there is an index, an events, events/index and an events/event route.

You can clone the repo here: https://github.com/baroquon/events-app/tree/start_0f_005.3

After you have cloned the repo cd into the app's root directory and run:

npm install && bower install

Now that we have our app set up we can run it and just take a look at what is going on here.

ember s

As you can see, we have an app with two primary routes, an index route and an events route. Clicking on the events route reveals three events which you can click on to see more details about the specific event.

So, now that we have seen the app, we are ready to generate our first acceptance test:

ember g acceptance-test events

Acceptance tests are different than integration tests in Ember in a couple of ways. Superficially, they tend to be more interaction driven. But, more importantly, in Ember, acceptance tests currently have access to different helpers than integration tests. Perhaps most significantly, acceptance tests boot and teardown your entire Ember application, including the router. While integration tests only stub out the surrounding context of the particular piece that is being tested. There is a big cost here with regard to test running speed. Integration tests are pretty fast while acceptance tests can be really slow. Although there are some addons, Ember Exam in particular, that can make your acceptance tests feel a bit faster under the right circumstances.

So, back to our working example. Here is our test as it currently exists in tests/acceptance/events-test.js:

import { test } from 'qunit';
import moduleForAcceptance from 'events-app/tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | events');

test('visiting /events', function(assert) {
  visit('/events');

  andThen(function() {
    assert.equal(currentURL(), '/events');
  });
});

Acceptance tests in Ember are pretty tightly associated with routing. Since we called our acceptance test 'events' Ember generated our test to expect to visit the events route. In most cases what we want to do with acceptance tests is:

  1. See that our page loads
  2. see that it contains some properties that we expect it to contain
  3. Interact with our page and assert that we get the expected result.

To accomplish these testing goals Ember provides a host of async and synchronous test helpers.

Our newly generated acceptance test will pass. As it currently exists, it is only testing that an events route exists. If we changed events to any non-existent route we could see our test fail.

We are going to create a simple assertion that when we visit the root url and click on the link to events we are taken to the events page. Then we will assert that our events list contains three items:

import { test } from 'qunit';
import moduleForAcceptance from 'events-app/tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | events');

test('visiting / and clicking events takes us to the events page.', function(assert) {
  visit('/');

  andThen(function() {
    click('a[href="/events"]');
    andThen(function() {
      assert.equal(currentURL(), '/events');
      // This is the text that is in the events/index template - it should display if we have not selected an event
      assert.equal($('article h3').text().trim(), "Choose an event on the left to see details");
      assert.equal($('aside ul li').length, 3);
    });
  });
});

Presently, the last assertion will pass as I have set up static data in the route. In the next drip, we will look at generating factories for both our acceptance tests and development environment using Ember CLI Mirage.

Resources