6

I have the following jasmine test:

it('should resolve promise', inject(function ($q, $rootScope) {

    function getPromise(){
        var deferred = $q.defer();
        setTimeout(function(){
            deferred.resolve(true);
        }, 1000);
        return deferred.promise;
    }

    var p = getPromise();
    var cb = jasmine.createSpy();

    runs(function(){
        expect(cb).not.toHaveBeenCalled();

        p.then(cb);

        $rootScope.$apply();
    });

    waitsFor(function(){
        return cb.callCount == 1;
    });

    runs(function(){
        expect(cb).toHaveBeenCalled();

        $rootScope.$apply();
    });

}));

I thought $rootScope.$apply was supposed to resolve all outstanding promises, but somehow it does not happen in this test.

How do i trigger promise resolving in a test like this? please help!

6
  • Which version of Angular are you using? With angularJS 1.2, promises are A+ compliant and they should resolve without an explicit call to execute the $digest loop. Commented Dec 1, 2013 at 11:20
  • 1
    i am using angular 1.2. Well i know they SHOULD resolve in the digest loop. But, they don't. :-( Commented Dec 2, 2013 at 15:58
  • Well, when i call $apply directly after resolve, it works. But i think this is still strange behavior. When i try to use the same solution in my real unit test (the one presented here is just for testing the $apply behavior) it fails. So, it seems i still have a problem! Commented Dec 2, 2013 at 16:14
  • Did only $scope.$apply work and not $timeout? I'll remove it from the solution if it didn't. Commented Dec 2, 2013 at 16:31
  • 1
    That rung a bell. The $timeout service is mocked by ngMock (Doh!) and one explicitly needs to call $timeout.flush(): plnkr.co/edit/Bdh78ZiArbO8vau9ByVJ?p=preview Commented Dec 2, 2013 at 16:52

1 Answer 1

12

I think the $rootScope.$apply() is being called too soon in your case. This should work:

function getPromise(){
    var deferred = $q.defer();
    setTimeout(function(){
        deferred.resolve(true);
        $rootScope.$apply();
    }, 1000);
    return deferred.promise;
}

Update

You can inject mock $timeout service and resolve the promise in that explicitly using $timeout.flush().

it('should resolve promise', inject(function ($q, $timeout, $rootScope) {

    function getPromise(){
        var deferred = $q.defer();
        $timeout(function(){
            deferred.resolve(true);
        }, 1000); 
        return deferred.promise;
    }

    // ...

    $timeout.flush();

    // ...
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.