How do I inject a controller into a mixin for testing?


#1

I have a mixin that has the following injection:

application: Ember.inject.controller(),

My unit test fails:

  var WorkflowCommonObject = Ember.Object.extend(WorkflowCommonMixin);
  var subject = WorkflowCommonObject.create(this.container);
  assert.ok(subject);;
});

with the following error:

Assertion Failed: Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.

How do I inject the controller into the mixin or how do i create the object via a container so my test would pass?

I have similar other scenarios where I need to inject services into the mixin but can’t figure out a way to stub the services. I tried the registring in the setup function but that doesn’t work in mixins - it worked everywhere else though.


#2

Try this:

var subject = WorkflowCommonObject.create({container: this.container});


#3

That didn’t fix it. Same error message.


#4

I don’t believe unit test gives you a container. Try integration test instead.


#5

I’ve been stubbing out dependencies in unit tests. As @lightblade suggests, an integration test might be better if you need the application controller to test your mixin.


#6

How would you stub the controller in this case so that the Ember.inject.controller() call succeeds?


#7

I use sinon so it’s going to look something like this (lets assume you’re calling foo on the application controller):

sinon.stub(Ember.inject, 'controller').returns({foo: -> ...})

This way, you’ll have {foo: -> ...} attached to this.application for your unit tests. You can also stub out different scenarios (i.e. success and failure) easily.

Now, there’s a lot that can go wrong if you’re only using unit tests (e.g. the Ember.inject api changes) so you do need to have integration tests that make sure the whole app sticks together.


#8

That’s great. I am going to try it out. Thanks.


#9

@eibrahim

I overlooked you were in the scope of a test. Which indeed doesn’t have a container. While an integration test might be what you need, you can do this in a unit test.

It used to be done something like this:

var app;
var container;
 
module('Module', {
	setup: function() {
		app = startApp();
		container=app.getContainer();
	},
	teardown: function() {
		Ember.run(app, app.destroy);
	}
});

test("Test", function( ) {
	var WorkflowCommonObject = Ember.Object.extend(WorkflowCommonMixin);
	var subject = WorkflowCommonObject.create({container: container});
	assert.ok(subject);;
}

#10

I wouldn’t use startApp to get a container in unit tests - try a helper instead that truly creates a registry. The example below works for anything not ember 2.3 (if you need 2.3+ look at this version of the helper)

import Ember from 'ember';
import {test} from 'qunit';
import {module as qunitModule} from 'qunit';

var module = function(name, settings){
    settings = settings || {};
    qunitModule(name, {
        beforeEach: function() {
            this.registry = new Ember.Registry();
            this.container = this.registry.container();
            if(typeof settings.beforeEach === 'function') {
                return settings.beforeEach.apply(this, arguments);
            }
        },
        afterEach: function() {
            this.container = null;
            this.registry = null;
            if(typeof settings.afterEach === 'function') {
                return settings.afterEach.apply(this, arguments);
            }
        }
    });
};

export { module, test };

Here is how you would use that helper to write a unit test that provides a full container/registry

import {test, module} from 'admin/tests/helpers/qunit';

module('unit: my unit test', {
    beforeEach() {
        // this.container
        // this.registry
    }
});

test('in this test you can do anything with the container', (assert) => {

});