Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular.js promise not resolving when unit testing service with karma

I am trying to unit test an Angular.js service, and need to set an expect on a promise returned from a Mock service (using Jasmine). I am using the karma unit testing framework. The relevant code snippet is below:

// I can't figure out how to do the equivalent of a $scope.$digest here. 
var loginStatusPromise = FacebookService.getFacebookToken();
loginStatusPromise.then(function(token) {
    expect(false).toBeTruthy(); // If this test passes, there is something going wrong!
    expect(token).not.toBeNull(); // The token should be ValidToken
    expect(token).toBe('ValidToken');
});

The complete unit test code can be seen here.

The problem is the promise.then statement never fires when karma is executing. Hence, none of my expect statements are executed. In my controller tests, I use $scope.$digest() to resolve the promises, but I am not clear on how to do this in a service test. As I thought there was no notion of 'scope' in a service test.

Do I have the wrong end of the stick here? Do I need to injecct $rootScope into my service test and then use $digest? Or, is there another way?

like image 241
Bradley Avatar asked May 07 '14 08:05

Bradley


Video Answer


3 Answers

I had this problem and resolved it by simply putting a $rootScope.$apply() at the end of my test

Your FacebookService might be the issue, as suggested by @mpm. Are you sure it doesn't have any http calls happening inside of that Facebook dependency which wouldn't be occurring during unit testing? Are you certain that resolve has been called on the deferred yet?

like image 194
bitwit Avatar answered Oct 08 '22 03:10

bitwit


Assuming that you are using ngFacebook/ngModule a quick note before the solution/ideas is that this project does not have unit tests ! Are you sure you want to use this project ?

I did a quick scan of your Unit Tests on Github and found following missing:-

1) Module initialization. ngFacebook needs that or you need to initialize your module that does the same thing.

beforeEach(module('ngFacebook'));

OR

beforeEach(module('yieldtome'));

2) Seriously consider mocking ngFacebook module

At unit level tests you are testing your code within a mocked bubble where outside interfaces are stubbed out.

Otherwise) Try adding calling the API as below:-

 $rootScope.$apply(function() {
     this.FacebookService.getFacebookToken().then(function(){
        //your expect code here
     });
    });
 $httpBackend.flush();//mock any anticipated outgoing requests as per [$httpBackend][2]
like image 2
bhantol Avatar answered Oct 08 '22 01:10

bhantol


beforeEach(function(){
   var self=this;
    inject(function($rootScope,Facebook){
        self.$rootScope=$rootScope;
        self.Facebook=Facebook;
    });
})

it('resolves unless sourcecode broken',function(done){
    // I can't figure out how to do the equivalent of a $scope.$digest here. 
    var loginStatusPromise = this.FacebookService.getFacebookToken();
    loginStatusPromise.then(function(token) {
        expect(token).toBe('ValidToken');
        done();
    });
    $rootscope.$apply();

});

https://docs.angularjs.org/api/ng/service/$q

like image 1
mpm Avatar answered Oct 08 '22 01:10

mpm