Jasmine unit tests not waiting for promise resolution

Viewed 17180

I have an angular service that has an async dependency like this

(function() {
    angular
        .module('app')
        .factory('myService', ['$q', 'asyncService',

    function($q, asyncService) {

        var myData = null;

        return {
            initialize: initialize,
        };

        function initialize(loanId){
            return asyncService.getData(id)
                .then(function(data){
                    console.log("got the data!");
                    myData = data;
            });
        }
    }]);
})();

I want to unit test the initialize function and I'm trying in jasmine like this:

describe("Rate Structure Lookup Service", function() {

    var $q;
    var $rootScope;
    var getDataDeferred;
    var mockAsyncService;
    var service;

    beforeEach(function(){
        module('app');

        module(function ($provide) {
            $provide.value('asyncService', mockAsyncService);
        });

        inject(function(_$q_, _$rootScope_, myService) {
            $q = _$q_;
            $rootScope = _$rootScope_;
            service = myService;
        });

        getDataDeferred = $q.defer();

        mockAsyncService = {
            getData: jasmine.createSpy('getData').and.returnValue(getDataDeferred.promise)
        };
    });

    describe("Lookup Data", function(){
        var data;

        beforeEach(function(){
            testData = [{
                recordId: 2,
                effectiveDate: moment("1/1/2015", "l")
            },{
                recordId: 1,
                effectiveDate: moment("1/1/2014", "l")
            }];
        });

        it("should get data", function(){
            getDataDeferred.resolve(testData);

            service.initialize(1234).then(function(){
                console.log("I've been resolved!");
                expect(mockAsyncService.getData).toHaveBeenCalledWith(1234);
            });

            $rootScope.$apply();
        });
    });
});

None of the console messages appear and the test seems to just fly on through without the promises ever being resolved. I though that the $rootScope.$apply() would do it but seems not to.

UPDATE

@estus was right that $rootScope.$appy() is sufficient to trigger resolution of all the promises. It seems that the issue was in my mocking of the asyncService. I changed it from

mockAsyncService = {
    getData: jasmine.createSpy('getData').and.returnValue(getDataDeferred.promise)
};

to

mockAsyncService = {
    getData: jasmine.createSpy('getData').and.callFake(
        function(id){
            return $q.when(testData);
    })
};

and I set testData to what I need to for the tests rather than calling getDataDeferred.resolve(testData). Prior to this change, the mockAsyncService was being injected but the promise for getDataDeferred was never being resolved.

I don't know if this is something in the order of injection in the beforeEach or what. Even more curious was that is has to be a callFake. Using .and.returnValue($q.when(testData)) still blocks promise resolution.

3 Answers
Related