Testing

Running existing tests

Running your Tests is as easy as one of these two commands:

ember test            # will run your test-suite in your current shell once
ember test --server   # will run your tests on every file-change

Alternatively you can run the tests in your regular browser using the QUnit interface. Run ember server and navigate to http://localhost:4200/tests. In this case, the tests will run in your default environment, usually ‘development’.

Writing a Test

  • ember-testing
  • helpers
  • unit/acceptance

The default tests in Ember CLI use the QUnit library. The included tests demonstrate how to write both unit tests and acceptance/integration tests using the new ember-testing package.

Test filenames should be suffixed with -test.js in order to run.

If you are using Pods to organize your application, be sure to add your podModulePrefix to the test resolver namespace.

If you have manually set the locationType in your environment.js to hash or none you need to update your tests/index.html to have absolute paths (/assets/vendor.css and /testem.js vs the default relative paths).

CI Mode with Testem

ember test will run your tests with Testem on CI mode. You can pass any option to Testem using a configuration file.

If you are capturing output from the Testem xunit reporter, use ember test --silent to silence unwanted output such as the ember-cli version.

By default, your integration tests will run on PhantomJS. You can install via npm:

npm install -g phantomjs

We plan to make your test runner pluggable, so you can use your favorite runner.

Using ember-qunit for integration tests

All Ember Apps come with built-in ember test helpers, which are useful for writing integration tests. In order to use them, you will need to import tests/helpers/start-app.js, which injects the required helpers.

Be sure to use the injected module function to invoke setup and teardown.

 1 import Ember from "ember";
 2 import { test } from 'ember-qunit';
 3 import startApp from '../helpers/start-app';
 4 var App;
 5 
 6 module('An Integration test', {
 7   setup: function() {
 8     App = startApp();
 9   },
10   teardown: function() {
11     Ember.run(App, App.destroy);
12   }
13 });
14 
15 test("Page contents", function() {
16   expect(2);
17   visit('/foos').then(function() {
18     equal(find('.foos-list').length, 1, "Page contains list of models");
19     equal(find('.foos-list .foo-item').length, 5, "List contains expected number of models");
20   });
21 });

Using ember-qunit for unit tests

An Ember CLI-generated project comes pre-loaded with ember-qunit which includes several helpers to make your unit-testing life easier, i.e.:

  • moduleFor
  • moduleForModel
  • moduleForComponent
moduleFor(fullName, description, callbacks, delegate)

The generic resolver that will load what you specify. The usage closely follows QUnit’s own module function. Its use can be seen within the supplied index-test.js:

 1 import { test, moduleFor } from 'ember-qunit';
 2 
 3 moduleFor('route:index', "Unit - IndexRoute", {
 4   // only neccessary if you want to load other items into the runtime
 5   // needs: ['controller:index']
 6   setup: function () {},
 7   teardown: function () {}
 8 });
 9 
10 test("it exists", function(){
11   ok(this.subject());
12 });

fullname

The resolver friendly name of the object you are testing.

description

The description that will group all subsequent tests under. Defaults to the fullname.

callbacks

You are able to supply custom setup, teardown, & subject functionality by passing them into the callbacks parameter. If other objects should be loaded into Ember.js, specify the objects through the needs property.

delegate

To manually modify the container & the testing context, supply a function as the delegate matching this signature delegate(container, testing_context).

this.subject() calls the factory for the object specified by the fullname and will return an instance of the object.

moduleForModel(name, description, callbacks)

Extends the generic moduleFor with custom loading for testing models:

 1 import DS from 'ember-data';
 2 import Ember from 'ember';
 3 import { test, moduleForModel } from 'ember-qunit';
 4 
 5 moduleForModel('post', 'Post Model', {
 6   needs: ['model:comment']
 7 });
 8 
 9 test('Post is a valid ember-data Model', function () {
10   var store = this.store();
11   var post = this.subject({title: 'A title for a post', user: 'bob'});
12   ok(post);
13   ok(post instanceof DS.Model);
14   
15   // set a relationship
16   Ember.run(function() {
17     post.set('comment', store.createRecord('comment', {}))
18   });
19   
20   ok(post.get('comment'));
21   ok(post.get('comment') instanceof DS.Model);
22 });

name

The name of the model you are testing. It is necessary to only supply the name, not the resolver path to the object(model:post => post).

description

The description that will group all subsequent tests under. Defaults to the name.

callbacks

You are able to supply custom setup, teardown, & subject functionality by passing them into the callbacks parameter. If other objects should be loaded into Ember.js, specify the objects through the needs property.

Note: If the model you are testing has relationships to any other model, those must be specified through the needs property.

this.store() retrieves the DS.Store.

this.subject() calls the factory for the DS.Model specified by the fullname and will return an instance of the object.

moduleForComponent(name, description, callbacks)

Extends the generic moduleFor with custom loading for testing components:

 1 import Ember from "ember";
 2 import { test, moduleForComponent } from 'ember-qunit';
 3 
 4 moduleForComponent('pretty-color');
 5 
 6 test('changing colors', function(){
 7   var component = this.subject();
 8 
 9   Ember.run(function(){
10     component.set('name','red');
11   });
12 
13   // first call to $() renders the component.
14   equal(this.$().attr('style'), 'color: red;');
15 
16   Ember.run(function(){
17     component.set('name', 'green');
18   });
19 
20   equal(this.$().attr('style'), 'color: green;');
21 });

name

The name of the component you are testing. It is necessary to only supply the name, not the resolver path to the object(component:pretty-color => pretty-color).

description

The description that will group all subsequent tests under. Defaults to the name.

callbacks

You are able to supply custom setup, teardown, & subject functionality by passing them into the callbacks parameter. If other objects should be loaded into Ember.js, specify the objects through the needs property.

this.subject() calls the factory for the Ember.Component specified by the fullname and will return an instance of the object.

The first call this.$() will render out the component. So if you want to test styling, you must access the component via jQuery.

Writing your own test helpers

Ember testing provides that ability to register your own test helpers. In order to use these with ember-cli they must be registered before startApp is defined.

Depending on your approach, you may want to define one helper per file or a group of helpers in one file.

Single helper per file

1 // helpers/routes-to.js
2 export default Ember.Test.registerAsyncHelper('routesTo', function (app, url, route_name) {
3   visit(url);
4   andThen(function () {
5     equal(currentRouteName(), route_name, 'Expected ' + route_name + ', got: ' + currentRouteName());
6   });
7 });

This can then be used in start-app.js, like this

1 // helpers/start-app.js
2 import routesTo from './routes-to';
3 
4 export default function startApp(attrs) {
5 //...

Group of helpers in one file

An alternative approach is to create a bunch of helpers wrapped in a self calling function, like this

 1 // helpers/custom-helpers.js
 2 var customHelpers = function() {
 3   Ember.Test.registerHelper('myGreatHelper', function (app) {
 4     //do awesome test stuff
 5   });
 6 
 7   Ember.Test.registerAsyncHelper('myGreatAsyncHelper', function (app) {
 8     //do awesome test stuff
 9   });
10 }();
11 
12 export default customHelpers;

which can be used in start-app.js

1 // helpers/start-app.js
2 import customHelpers from './custom-helpers';
3 
4 export default function startApp(attrs) {
5 //...

Once your helpers are defined, you’ll want to ensure that they are listing in the .jshintrc file within the test directory.

1 // /tests/.jshintrc
2 {
3   "predef": [
4     "document",
5     //...
6     "myGreatHelper",
7     "myGreatAsyncHelper"