4

I have a recursive method that, if a flag is set, will call itself every five seconds. I'm trying to write a test that spies on the method, calls it, waits six seconds and then expects the method to have been called twice. My test fails, as the spy reports the method only being called once (the initial call).

I'm using the Angular style guide, so am attaching these methods to a placeholder for this. I suspect there may be an issue with scoping of the controller returned from angular-mocks $controller(), but I'm not sure—most people are attaching methods to $scope.

Without attaching methods to $scope, how can I create a spy to verify that my method has been called twice?

app.js:

'use strict';

angular
    .module('MyApp', [
        //...
    ]);

angular
    .module('MyApp')
    .controller('MyController', MyController);

MyController.$inject = [
    //...
];

function MyController() {
    var vm = this;

    vm.callMyself = callMyself;
    vm.flag = false;

    function callMyself () {
        console.log('callMyself');
        if (vm.flag) {
            console.log('callMyself & flag');
            setTimeout(vm.callMyself, 5000);
        }
    }
}

appSpec.js:

describe('MyController', function () {

    var $scope;

    beforeEach(function () {
        module('MyApp');
    });

    beforeEach(inject(function($rootScope, $controller) {
        $scope = $rootScope.$new();
        controllerInstance = $controller('MyController', {$scope: $scope});
    }));

    it('should call itself within 6 seconds if flag is true', function (done) {
        controllerInstance.flag = true;
        spyOn(controllerInstance, 'callMyself');
        controllerInstance.callMyself();
        setTimeout(function () {
            expect(controllerInstance.callMyself).toHaveBeenCalledTimes(2);
            done();
        }, 6000);
    }, 7000);
});

Working Plunker

1 Answer 1

5

You need to use .and.callThrough() to further execute the function that would call itself:

By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation.

spyOn(controllerInstance, 'callMyself').and.callThrough();

Tested in the plunker - it works.

Sign up to request clarification or add additional context in comments.

1 Comment

I've spent a while looking for how to test recursion, never thought it would be so easy, and other pages/answers recommending huge codes, great contribution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.