2

I'm having a hard time to get my head around Jasmine. The following test is failing with the message "Expected spy init to have been called. at Object.."

The Test

beforeEach(module('myModule'));

it('Should execute myCtrl.init() on controller instantiation', function () {
        var $scope = $rootScope.$new();

        $scope.foo = 'bar';

        var MyCtrl = $controller('MyCtrl', {
            $scope: $scope
        });

        spyOn($scope, 'init');

        expect($scope.init).toHaveBeenCalled();
        expect($scope.foo).toBe('bar');

});

The Controller

angular.module('myModule')

.controller('MyCtrl', [
'$scope'
function($scope) {

    $scope.init = $scope.init || function init () {
        $scope.foo = $scope.foo || 'baz';
    };

    $scope.init();

}]);

What am I missing?

6
  • 1
    What are you trying to achieve via $scope.init = $scope.init || function init () { $scope.foo = $scope.foo || 'baz'; };? Commented Sep 17, 2015 at 20:51
  • @DianaR This is a generic controller that I'm coding. The programmer can use the default controller methods or create their own, by overwriting the pre existing ones. The controller is going to have 3 or 4 default methods. Commented Sep 17, 2015 at 21:04
  • 2
    There's really no point in checking that init() is called. What you should test is that the scope is correctly initialized, i.e. has $cope.foo equal to 'baz'. Commented Sep 17, 2015 at 21:04
  • 1
    Ah, ok. Indeed that no reason to spy on scope, just check that after controller creation, the data exists in the scope as expected. Commented Sep 17, 2015 at 21:07
  • 1
    @darksoulsong In general, you shouldn't spy what you're testing. You should spy the dependencies of what you're testing. You indeed can't spy a scope method that way, since the method doesn't exist until it's created when instantiating the controller. So if you spy after creating the controller, it's too late: the spied method has already been called. And if you spy before, it's too soon: the method doesn't exist yet. Commented Sep 17, 2015 at 21:51

1 Answer 1

3

Basically, you can't setup the spy after the controller is created, or it won't catch the method being called at controller invocation. But that is not something that really needs to be tested because you can tell based on the controller code that it is getting called when the controller is invoked, and the only thing that would keep it from being called is some kind of syntax error or something.

You are ok to test whether some $scope property like $scope.foo is set to the correct value, though.

This seems like a similar problem to AngularJs unit test - Check if "Init" function was called

Edit: If you really needed to though, you could use a scope mock like this (This is what you should do to mock other dependencies you might have to your controller) and inject it instead of the $rootScope way, but then you wouldn't have $scope.foo getting set because $scope.init would not be initially undefined:

var scopeMock;
beforeEach(module('myModule'));

it('Should execute myCtrl.init() on controller instantiation', function () {

    scopeMock = jasmine.createSpyObj('$scope', ['init']);

    var MyCtrl = $controller('MyCtrl', {
        $scope: scopeMock
    });

    //This will be true according to the controller you defined
    expect(scopeMock.init).toHaveBeenCalled();
});
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.