jackysee
jackysee

Reputation: 2061

How to test promise in angularjs

I've come across a case where I simply can't make the test passed.

Here is the test:

it('should accept an fucntion run it immediately', inject(function($rootScope, ready) {
    var spy = jasmine.createSpy('ready').andCallFake(function(){
        console.log("I'm ready");
    });
    ready.done(spy);
    expect(spy).toHaveBeenCalled();
}));

Here is code:

angular.module('myApp').factory('ready', function($q, _, $rootScope){

    var defer = $q.defer();

    //in real case it's actually calling 3rd party code, so no $timeout
    _.defer(function(){
        $rootScope.$apply(function(){
            defer.resolve();
        });
    });

    return {
        done: function(fn){
            defer.promise.then(fn);
        }
    };
});

The log of I'm ready did appeared but the test still failed. So I think its just the problem of handling async flow in jasmine. But I can't think of to test it using jasmine's runs and waitsFor.

Upvotes: 1

Views: 499

Answers (1)

Michal Charemza
Michal Charemza

Reputation: 26982

I suspect the test is failing, and then the console.log appears, in that order, as the promise isn't resolved until after the _.defer has called its callback, which is after the current call stack is cleared.

What you need is a way to force the underscore/lodash _.defer, to call its callback/promises, so your promise in the factory gets resolved immediately. If you were using $timeout, you could call $timeout.flush() in the test, but as far as I know underscore/lodash doesn't have anything like this.

However, before the test, you should be able to inject a mock '_', with a defer function, that calls its callback immediately:

beforeEach(module(function($provide) {
  $provide.value('_', {
    'defer': function(callback) {callback()};
  });    
}));

In your real case, you would need to do something like the above, by injecting a mock 3rd party service and forcing it to complete, so your promise gets resolved before the expect call in the test.

If for some reason you can't inject a mock version of the 3rd party code, you can make the test asynchronous, as explained at http://pivotal.github.io/jasmine/#section-Asynchronous_Support, but this should be avoided if possible, as it makes the test runs slower.

Upvotes: 1

Related Questions