Florian F
Florian F

Reputation: 8875

AngularJS : Need help to unit test a factory with promise

I have a factory that uses a promise to resolve a json file. It should only resolve this file the first time and return the result when called again.

Here is the factory

app.factory('getServerConfig', function ($q, $http, serverConfig) {

  return function (fileName) {
    var deferred = $q.defer();

    if (serverConfig.loaded) {
      deferred.resolve("alreadyLoaded");
    } else {
      $http.get(fileName).then(function (result) {
        serverConfig.setConfig(result.data);
        deferred.resolve("loaded");
      }, function (result) {
        deferred.reject();
      });
    }
    return deferred.promise;
  };
})

And how I test it :

it('should say hallo to the World', inject(function(getServerConfig) {
    var promiseResult;

    getServerConfig("server-config.json").then(function (result) {
      promiseResult = result;
    });

    rootScope.$apply();
    expect(promiseResult).toBe('loaded');
}));

Unfortunately, it looks likes promiseResult is never set. Here is a plunker with the code : http://plnkr.co/edit/uRPCjuUDkqPRAv07G5Nx?p=preview

Upvotes: 2

Views: 3148

Answers (1)

Caio Cunha
Caio Cunha

Reputation: 23394

The problem is that $httpBackend demands a flush() (take a look at Flushing HTTP requests), so you can mimic $http asynchronous behavior in your test.

To solve it, store a reference of $httpBackend (or inject it again) and call $httpBack.flush() after the request has been made.

Look:

it('should say hallo to the World', inject(function(getServerConfig, $httpBackend) {
  var promiseResult;

  getServerConfig("server-config.json").then(function (result) {
    promiseResult = result;
  });

  $httpBackend.flush();
  expect(promiseResult).toBe('loaded');
}));

If you gonna use $httpBackend in most of your specs, consider storing it in a local variable, and set it in beforeEach.

Upvotes: 3

Related Questions