Search code examples
angularjsdependency-injectionhttpbackendangular-mock

how is angular mock's httpBackend passed implicitly to the $controller service in tests?


This spec passes, even though it looks like it should fail. (the code is from a book on angular and rails)

here is the angular app:

var app = angular.module('customers',[]);

app.controller("CustomerSearchController",
  ["$scope", "$http", function($scope, $http) {
    var page = 0;
    $scope.customers = [];
    $scope.search = function (searchTerm) {
      if (searchTerm.length < 3) {
        return;
      }
      $http.get("/customers.json",
        { "params": { "keywords": searchTerm, "page": page } }
      ).then(function(response) {
          $scope.customers = response.data;
        },function(response) {
          alert("There was a problem: " + response.status);
        }
      );
    };
  }
]);

and, here is the Jasmine spec:

describe("Error Handling", function () {
  var scope = null,
    controller = null,
    httpBackend = null;
  beforeEach(module("customers"));
  beforeEach(inject(function ($controller, $rootScope, $httpBackend) {
    scope = $rootScope.$new();
    httpBackend = $httpBackend;
    controller = $controller("CustomerSearchController", {
      $scope: scope
    });
  }));
  beforeEach(function () {
    httpBackend.when('GET', '/customers.json?keywords=bob&page=0').respond(500, 'Internal Server Error');
    spyOn(window, "alert");
  });
  it("alerts the user on an error", function() {
    scope.search("bob");
    httpBackend.flush();
    expect(scope.customers).toEqualData([]);
    expect(window.alert).toHaveBeenCalledWith(
      "There was a problem: 500");
    });

});

I don't understand how the controller is ever getting access to the $httpBackend service, injected into the anonymous function passed to inject in the beforeEach method. The $scope service is passed in, but httpBackend isn't.


Solution

  • $controller doesn't depend on $httpBackend service, $httpBackend isn't passed to it.

    $http depends on $httpBackend (hence the name). $httpBackend is overridden in ngMock with mocked implementation and used by $http instead of the original $httpBackend (which isn't intended for direct use).