Unit Testing Controller with init method accessing model


#1

HI, I have a controller which has its init method overridden and in the init method I access the controllers model. Now when I try to test this controller using modelFor, I get error at the line where I acess model properties. It says model is undefined.

I am not sure how to handle this issue. Is there a way to provide the controller a Model object in setup method? I cannot do this.subject().set(‘model’, …) as it calls the init method and it fails again.

Please let me know if I am not clear, will be happy to provide more information.


#2

Consider following example:

Controller Code:

import Ember from 'ember';
export default Ember.ObjectController.extend({
  isDraft: function(){
    return this.get('state') === 'draft';
  }.property('state')
});

Test for above controller

import Ember from "ember";
import DS from "ember-data";
import { test, moduleFor } from 'ember-qunit';

moduleFor('controller:offer/index', 'Offer Controller', {
});

test('isDraft value', function () {
  expect(2);
  var ctrl = this.subject();
  Ember.run(function() {
    ctrl.set('model', Ember.Object.create({ state: '' }));
    // check the values before we modify the offer
    equal(ctrl.get('isDraft'), false);
    // modify the state of the offer
    ctrl.get('model').set('state', 'draft');
    // assert that the controllers isDraft has changed
    equal(ctrl.get('isDraft'), true);
  });
});

Hope this examplw would help you to understand it more better. Thanks.


#3

Hi Swati, Yes I know how to inject a model for normal methods. But the init method is called at the controller creation or initialization. So its invoked when you call this.subject() and there in lies the issue. At that point of time the model is not available.


#4

The only thing I could think of is to use lookupFactory. http://jsfiddle.net/NQKvy/1266/ Perhaps you can change the functionality of subject for this particular test since it exposes the container without having to pluck off the Application’s container.

Edit: But I agree with Robert, you can’t typically rely on the controller to have a model when it’s instantiated. I think the edge-case there would be if it’s an itemController or a controller you’re managing (like in my fiddle example).


#5

In general you should not rely on having the model at instantiation time of your controller. Your controller will normally be looked up and instantiated before the model is available. The routes setupController hook is what sets the model on the controller, but it receives an already instantiated controller.

If you DO need to test things with ember-qunit that require certain properties to be set on init, you can provide those properties to the this.subject call:

moduleFor('controller:something');

test('do stuff', function() {
  var controller = this.subject({
    someProp: 'I exist when init is called'
  });

  ok(controller.get('someProp');
});

#6

Thanks for the response guys. Jason you guessed it right I am indeed using an ItemController in this case and need the model to be there. Sorry should have been clear in the first place.

Jason , Thanks for the fiddle, will look in to it.

rwjblue I remember I did try that, had some issues. Will give it a shot again.