anjunatl
anjunatl

Reputation: 1057

Angular $http.get success handler not called in Jasmine unit test

I have a very basic factory service that I would like to unit test. I have tried $rootScope.$digest() and $rootScope.$apply() before the expect statements and neither the success or failure handlers are being called at all in the unit test - they are called fine in the app in the context of the controller that's using this factory, though.

example.service.js:

(function (angular) {
  'use strict';

  angular
    .module('exampleModule')
    .factory('ExampleApi', ExampleApi);

  ExampleApi.$inject = ['$http'];
  function ExampleApi($http) {
    return {
      get: getExampleData
    }

    function getExampleData() {
      return $http.get('example-endpoint');
    }
  }

})(angular);

example.service.spec.js

'use strict';

describe('Example API service', function() {
  var $httpBackend;
  var $rootScope;
  var ExampleApi;

  beforeEach(module('exampleModule'));

  beforeEach(inject(
    function(_$httpBackend_, _$rootScope_, _ExampleApi_) {
      $httpBackend = _$httpBackend_;
      $rootScope = _$rootScope_;
      ExampleApi = _ExampleApi_;
  }));

  it('calls the success handler on success', function() {
    $httpBackend
      .expectGET('example-endpoint')
      .respond(200);

    var handlerStubs = {
      success: function() {
        console.log("success called");
      },
      failure: function() {
        console.log("failure called");
      }
    }

    spyOn(handlerStubs, 'success').and.callThrough();
    spyOn(handlerStubs, 'failure').and.callThrough();
    ExampleApi.get().then(handlerStubs.success, handlerStubs.failure);
    //$rootScope.$digest();
    $rootScope.$apply();
    expect(handlerStubs.failure.calls.count()).toEqual(0);
    expect(handlerStubs.success.calls.count()).toEqual(1);
  });
});

Upvotes: 0

Views: 283

Answers (1)

Luke Hutton
Luke Hutton

Reputation: 10722

$httpBackend mock contains a flush() method, which when called, will resolve the get request giving you synchronous control of the code under test. When $httpBackend.flush(); is called, the expectation .expectGET is verified.

From the Angular Docs:

The $httpBackend used in production always responds to requests asynchronously. If we preserved this behavior in unit testing, we'd have to create async unit tests, which are hard to write, to follow and to maintain. But neither can the testing mock respond synchronously; that would change the execution of the code under test. For this reason, the mock $httpBackend has a flush() method, which allows the test to explicitly flush pending requests. This preserves the async api of the backend, while allowing the test to execute synchronously.

Upvotes: 1

Related Questions