简体   繁体   中英

Angular unit test a service return Promise Jasmine

I followed this tutorial to make unit test for a service that return a Promise but could not get it worked.

My service returns a Promise that will retrives HTML5 geolocation.

app.factory('getGeo', function() { 
     return function(){
         return new Promise(function (resolve, reject) {
         navigator.geolocation.getCurrentPosition(resolve, reject, options);
          });        
       }
      var options = {
         enableHighAccuracy: true,
         timeout: 5000,
          maximumAge: 0
          };         
});

And my controller has a function that resolve the Promise to set some states in the app.

getGeo().then((position) => {
          //perform logic when geo is received
          $scope.weatherInfo.la = position.coords.latitude;//new properties
          $scope.weatherInfo.lo = position.coords.longitude;//new properties
          $scope.weatherInfo.url = `http://api.openweathermap.org/data/2.5/weather?lat=${$scope.weatherInfo.la}&lon=${$scope.weatherInfo.lo}&appid=0d00180d180f48b832ffe7d9179d40c4`;
        })

And my test:

beforeEach(inject(function(_$rootScope_, _getGeo_){
   $rootScope = _$rootScope_;
   $getGeo = _getGeo_;
 }));

describe('getGeo method', function() {
  it('getGeo should return a promise', function() {
    var $scope = $rootScope.$new();
    var position = {coords:{coords:{latitude:'1',latitude:'3'}}};
    $getGeo().then(function(position) {
    expect($scope.weatherInfo.url).not.toBeNull();
    done();
   });
   $scope.$digest();                
 });
});

I got this SPEC HAS NO EXPECTATIONS getGeo should return a promise . Seems the code inside the mock service never gets called. But if I move out the expect($scope.weatherInfo.url).not.toBeNull() and put it under $scope.$digest() I'd get a Cannot read property 'url' of undefined error.

  1. var position = {coords:{coords:{latitude:'1',latitude:'3'}}}; $getGeo().then(function(position) { expect($scope.weatherInfo.url).not.toBeNull(); }

Variable in callback - it is the data which promise will return. It is not your var position = {coords:{coords:{latitude:'1',latitude:'3'}}};

  1. I think you shouldn't call the factory in the test. The factory will call constructor only one time when you inject its first. So you just need to make next

    $getGeo.then(function(position) {...})

  2. Your factory takes data from outside navigator.geolocation.getCurrentPosition() . So you need to make stub for it.

    spyOn(navigator.geolocation, 'getCurrentPosition').andReturn(/* here is the data which you expected */)

It is hard to show you the full example. However, I tried to describe critical things.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM