Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit-testing a controller that uses $http

I have a simple controller and the first thing I need it to do is assign a value to scope.

function TestCtrl($scope, $http) {
    $scope.listForms = 'some list';
}

The following test for the controller works as expected:

describe('Testing a controller', function() {

    var ctrl, scope, httpMock;

    beforeEach(inject(function($injector) {
        scope = $injector.get('$rootScope').$new();
        ctrl = $injector.get('$controller');
        ctrl(TestCtrl, { $scope: scope });
    }));

    it("assigns to scope", function() {
      expect(scope.listForms).toMatch("some list");
    });
});

But when I change the function to get the list from my API

function TestCtrl($scope, $http) {
  $http.get('/api/listForms').success(function(list) {
    $scope.aListOfForms = 'some list';
  });
}

and the test changes to

describe('Testing a controller', function() {

    var ctrl, scope, httpMock;

    beforeEach(inject(function($injector) {
        httpMock = $injector.get('$httpBackend');

        scope = $injector.get('$rootScope').$new();
        httpMock.when('GET', '/tactical/api/listOrderForms').respond("an order form");

        ctrl = $injector.get('$controller');
        ctrl(TestCtrl, {
            $scope: scope,
            $http: httpMock
        });
    }));

    it("gets the list from the api and assigns it to scope", function() {
      httpMock.expectGET('tactical/api/listOrderForms');
      expect(scope.orderFormList).toMatch("an order form");
      httpMock.flush();
    });
});

I get the following errors:

TypeError: 'undefined' is not a function
Expected undefined to match 'an order form'.
Error: No pending request to flush !

Does anyone know what I am doing wrong? Thanks in advance.

like image 817
Richard V Avatar asked Mar 20 '13 16:03

Richard V


2 Answers

$http uses $httpBackend to talk to external resources. You have mocked $httpBackend, but the controller still needs to talk to it trough $https interface.

This should do it:

describe('Testing a controller', function() {

    var ctrl, scope, httpMock;

    beforeEach(inject(function($controller, $rootScope, $httpBackend) {
        httpMock = $httpBackend;

        scope = $rootScope.$new();
        httpMock.when('GET', '/tactical/api/listOrderForms').respond("an order form");

        ctrl = $controller;
        ctrl(TestCtrl, {
            $scope: scope
        });
    }));

    it("gets the list from the api and assigns it to scope", function() {
      httpMock.expectGET('tactical/api/listOrderForms');
      httpMock.flush();
      expect(scope.orderFormList).toMatch("an order form");
    });
});
like image 188
Kenneth Lynne Avatar answered Oct 27 '22 21:10

Kenneth Lynne


you can't replace $http service as $httpBackend service for your controller manually.

Change

    ctrl(TestCtrl, {
        $scope: scope,
        $http: httpMock
    });

to

    ctrl(TestCtrl, {
        $scope: scope
    });

It should work.

like image 23
Paul Lan Avatar answered Oct 27 '22 21:10

Paul Lan