Day 8 (week 2) — Testing in EmberJS

There are 3 keys ways to test your app.

  1. Acceptance testing — the test acts as a user would, interacting with the app by loading pages and clicking links, and we verify that correct actions are taken.
  2. Unit testing — we verify an isolated piece of code and that it responds correctly to inputs.
  3. Integration testing — sits in between unit and acceptance testing and makes sure that interactions between different parts of your app work correctly.

Testing is made particularly easy in Ember through its use of the ember generate acceptance-test and QUnit.

First up were some acceptance testing. Here, I just wrote a small test to make sure that we could delete a bookmark.

import { test } from 'qunit';
import moduleForAcceptance from 'ember-bookmarker/tests/helpers/module-for-acceptance';
moduleForAcceptance('Acceptance | bookmark delete');
test('visiting /bookmark-delete', function(assert) {
let user = server.create('user', {});
let bookmark = server.create('bookmark', {
title: 'Test Bookmark',
userId: user.id
});
visit(`/bookmarks/edit/${bookmark.id}`);
click('button#delete');
andThen(function() {
assert.equal(currentURL(), '/bookmarks');
})
});

The neat part to look at is the test method which sets up a user and a bookmark, then visit() is called to view that individual bookmark. Then we call click() to simulate the user clicking on the delete button. I don’t actually verify that this particular bookmark has been deleted. Only that we are redirected to the main bookmarks index page. Regardless, it would be pretty straightforward to check any number of conditions in the andThen function.

Next up were some model tests. In this case, we are just going to test and make sure that the nullName helper function returns the appropriate combination of firstName and lastName.

import { moduleForModel, test } from 'ember-qunit';
moduleForModel('user', 'Unit | Model | user', {
// Specify the other units that are required for this test.
needs: ['model:bookmark']
});
test('fullName returns correct join of first and last', function(assert) {
let model = this.subject({firstName: 'foo', lastName: 'bar'});
assert.equal(model.get('fullName'), 'foo bar', 'valid fullname');
});

The assert.equal just makes sure that a call to .get('fullName') returns the correct combination of foo bar — which is just a simulated first and last name from the model we created on the line before.

Last, I wrote a component test. In some ways component tests are probably the most important type of tests since they make sure that the app is rendering the correct templates and content. Here is the component test I wrote to make sure that the class of the img tag is set to 'avatar'.

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('users-list', 'Integration | Component | users list', {
integration: true
});
test('img class is set to avatar', function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
this.render(hbs`{{users-list fake-url sample-email}}`);
assert.equal(this.$('img').attr('class'), 'avatar');
// Template block usage:
this.render(hbs`
{{#users-list fake-url sample-email}}
template block text
{{/users-list}}
`);
assert.equal(this.$('img').attr('class'), 'avatar');
});

The two assert.equal statements are where we grab the class attribute from the img tag of the rendered page and check to make sure it is set to 'avatar'.

There are a lot of things you can do with testing an Ember app, and these are just scratching the surface of what can be done. What I found really nice is that you can start the Ember app and run the test server through the command line and then as you implement tests and save the file, the tests are automatically run and you can see which tests pass and which tests fail. Very nice.