Container testing methods and computed properties follows previous patterns shown in Testing Basics because Ember.Controller extends Ember.Object.
Controllers can be tested using the setupTest
helper which is part
of the ember-qunit framework. The tests written for instances like Ember.Controller
are
also described as container tests.
Testing Controller Actions
Here we have a controller PostsController
with two properties, a method that
sets one of those properties, and an action named setProps
.
You can follow along by generating your own controller with
ember generate controller posts
.
import Controller from '@ember/controller';
export default Controller.extend({
propA: 'You need to write tests',
propB: 'And write one for me too',
setPropB(str) {
this.set('propB', str);
},
actions: {
setProps(str) {
this.set('propA', 'Testing is cool');
this.setPropB(str);
}
}
});
The setProps
action directly sets one property, and calls the method to set the other.
In our generated test file, Ember CLI already uses the module
and the setupTest
helpers to set up a test
container:
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | posts', function(hooks) {
setupTest(hooks);
});
Next we use the owner API to gain access to the controller we'd like to test.
Using the this.owner.lookup
method we get the instance of the PostsController
and can check the action in our test.
The this.owner.lookup
helper returns objects generated by the framework in your applications
and is also exposed in tests for your usage. Here it will return a singleton instance of the PostsController
.
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | posts', function(hooks) {
setupTest(hooks);
test('should update A and B on setProps action', function(assert) {
assert.expect(4);
// get the controller instance
let controller = this.owner.lookup('controller:posts');
// check the properties before the action is triggered
assert.equal(controller.get('propA'), 'You need to write tests', 'propA initialized');
assert.equal(controller.get('propB'), 'And write one for me too', 'propB initialized');
// trigger the action on the controller by using the `send` method,
// passing in any params that our action may be expecting
controller.send('setProps', 'Testing Rocks!');
// finally we assert that our values have been updated
// by triggering our action.
assert.equal(controller.get('propA'), 'Testing is cool', 'propA updated');
assert.equal(controller.get('propB'), 'Testing Rocks!', 'propB updated');
});
});
Testing Controller Needs
Sometimes controllers have dependencies on other controllers. This is
accomplished by injecting one controller into another. For example, here are two simple controllers. The
CommentsController
uses the PostController
via inject
:
You can follow along by generating your own controller with
ember generate controller post
, andember generate controller comments
.
import Controller from '@ember/controller';
import { alias } from '@ember/object/computed';
export default Controller.extend({
title: alias('model.title')
});
import Controller, { inject as controller } from '@ember/controller';
import { alias } from '@ember/object/computed';
export default Controller.extend({
post: controller(),
title: alias('post.title')
});
Now let's write a test that sets a property on our post
model in the
PostController
that would be available on the CommentsController
.
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import EmberObject from '@ember/object';
import { run } from '@ember/runloop';
module('Unit | Controller | comments', function(hooks) {
setupTest(hooks);
test('should modify the post model', function(assert) {
assert.expect(2);
// grab an instance of `CommentsController` and `PostController`
let controller = this.owner.lookup('controller:comments');
let postCtrl = controller.get('post');
// wrap the test in the run loop because we are dealing with async functions
run(function() {
// set a generic model on the post controller
postCtrl.set('model', Ember.Object.create({ title: 'foo' }));
// check the values before we modify the post
assert.equal(controller.get('title'), 'foo', 'title is set');
// modify the title of the post
postCtrl.get('model').set('title', 'bar');
// assert that the controllers title has changed
assert.equal(controller.get('title'), 'bar', 'title is updated');
});
});
});