How to unit test an ember controller

1.9k views Asked by At

I have a single action defined in an ember controller that calls 2 separate functions that are part of the controller. I'd like to mock out those functions in a unit test in order to confirm if the action method called the correct function.

My controller looks like this:

export default Ember.Controller.extend({
    functionA() {
        return;
    },
    functionB() {
        return;
    },
    actions: {
        actionMethod(param) {
            if(param) {
                return this.functionA();
            }
            else {
                return this.functionB();
            }
         }
    }
});

In practice, the controller works, however in the unit test, functionA and functionB are both undefined. I tried to log this to the console, but can't find where functionA and functionB are, so I'm unable to properly mock them. I expected them to be in the top level of the object next to actions, but instead I only found _actions with actionMethod properly defined.

My unit test looks like below

const functionA = function() { return; }
const functionB = function() { return; }
test('it can do something', function(assert) {
    let controller = this.subject();
    // I don't want the real functions to run 
    controller.set('functionA', functionA);
    controller.set('functionB', functionB);
    controller.send('actionMethod', '');
    // raises TypeError: this.functionA is not a function

    // this doesn't work etiher
    // controller.functionB = functionB;
    // controller.functionA = functionA;
    // controller.actions.actionMethod();
}

Does anyone have any ideas on how I can replace those functions in the testing environment? Or perhaps, is there a better way to test this functionality or set up my controller?

  • edit typo: this.subject to this.subject()
2

There are 2 answers

0
ykaragol On BEST ANSWER

To replace the functions of the controller in the unit test, you can pass parameter to the this.subject() function:

 let controller = this.subject({
     functionA(){
         //this function overriddes functionA
     },
     functionB(){
         //this function overriddes functionB
     },
 });

Look at the sample twiddle.

This method is especially useful for replacing the injected service of the controllers.

2
Ember Freak On

Introduce corresponding property you are dealing with, let us say name property, So your controllers would be looking like this,

import Ember from 'ember';
export default Ember.Controller.extend({
  name:'',
  functionA() {
        this.set('name','A');
    },
    functionB() {
        this.set('name','B');
    },
    actions: {
        actionMethod(param) {
            if(param) {
                return this.functionA();
            }
            else {
                return this.functionB();
            }
         }
    }
});

And you can test for the name property value after calling actionMethod.

test(" testing functionA has been called or not", function(assert){
  let controller = this.subject();
  controller.send('actionMethod',true);
  //If you would like to call functionA just say  controller.functionA()
  assert.strictEqual(controller.get('name'),'A',' name property has A if actionMethod arguments true');
  controller.send('actionMethod',false);
  assert.strictEqual(controller.get('name'),'B',' name property has B actionMethod arguments false');
});