boatcoder
boatcoder

Reputation: 18107

Unit-testing, waiting on a promise when $http does NOT get invoked

I have a unittest where a service returns a promise. Sometimes that service might make a $http request, sometimes it won't (It implements a cache of sorts). In either case, it resolves the promise, but only in $httpBackend.flush() does it actually get around to making the callbacks. How can I cause the promises that are resolved to actually call the functions in the .then() like flush() does.

This one works just fine

resolved = jasmine.createSpy();
rejected = jasmine.createSpy();
employeeEventService.loadSchedules()
    .then(resolved, rejected);

$httpBackend.flush();  // This causes the promise to resolve/reject

expect(resolved).toHaveBeenCalled();
expect(rejected).not.toHaveBeenCalled();

This one doesn't work because I can't call flush() (since the service never called $http)

resolved = jasmine.createSpy();
rejected = jasmine.createSpy();
employeeEventService.loadSchedules()
    .then(resolved, rejected);

//$httpBackend.flush();  // Can't call this because this call is "cached"

expect(resolved).toHaveBeenCalled();
expect(rejected).not.toHaveBeenCalled();

Service code:

if(loaded.startOn <= params.startOn && loaded.endOn >= params.endOn
   && new Date() - lastFetch < 60000) {
     deferred.resolve(loaded.schedules);
} else {
    service.loading +=1;
    config = {params: params, timeout:30*1000};
    $http.get('/api/employee-schedules/', config)
        .then(function(response) {
            ...
            process the json response
            ...
            deferred.resolve(loaded.schedules);
         }, function(reason, status) {
            $log.error("Failed to get schedules", reason, status);
            deferred.reject(reason, status);
         })
         .finally(function() {
              service.loading -=1;
         });
}
return deferred.promise;

Upvotes: 2

Views: 2698

Answers (2)

MBielski
MBielski

Reputation: 6620

All promises, regardless of what pattern they are in, are resolved when you call $scope.$digest();

Upvotes: 3

SomeKittens
SomeKittens

Reputation: 39532

You're using a promise antipattern in your service, which is why you're encountering these issues. Instead, try this pattern:

function loadSchedules () {
  return (cachedSchedules) ? $q.when(cachedSchedules) : asyncHTTPStuffs();
}

(Thanks to Benjamin Gruenbaum)

This way, you can return a thenable object, regardless of cache status, while not needing to call $httpBackend.flush() if you know the data is cached.

Upvotes: 2

Related Questions