Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing AngularJS controller with $httpBackend

For the life of me I can't get $httpBackend to work on a controller that does an $http get request. I've tried for hours now =)

I've reduced this to the simplest form I can below. The test passes if I

  • comment out the $http.get() request in the controller
  • comment out the "httpMock.flush()" in the test
  • and change "pig" and "dog" to match

That is, it's a valid, working test and app.

If I put it back in, I get the error shown at the bottom.


app/js/app.js

// Declare a module which depends on filters and services.
var myApp = angular
  .module('myApp', ['ngRoute', 'myApp.filters', 'myApp.services',
                              'myApp.directives'])
  .config(['$routeProvider' , function($routeProvider) {

    $routeProvider
      .when("/dashboard", {
        templateUrl: "partials/dashboard.html",
        controller: cDashboard
      })

      .otherwise({redirectTo: "/dashboard"});
  }]);

// Pre-define our main namespace modules.
angular.module('myApp.directives' , []);
angular.module('myApp.filters'    , []);
angular.module('myApp.services'   , []);
angular.module('myApp.controllers', []);

app/js/controller.js

function cDashboard ($scope, $http) {
  $scope.data = "dog";

  // Fetch the actual data.
  $http.get("/data")
    .success(function (data) { $scope.data = data })
    .error(function () {});
}

cDashboard.$inject = [ '$scope', '$http' ];

test/unit/controllerSpec.js

describe('cDashboard', function(){
  var scope, ctrl, httpMock;

  beforeEach(inject(function ($rootScope, $controller, $http, $httpBackend) {
    scope = $rootScope.$new();
    ctrl = $controller('cDashboard', {$scope: scope});

    httpMock = $httpBackend;
    httpMock.when("GET", "/data").respond("pig");
  }));

  it("should get 'pig' from '/data'", function () {
    httpMock.expectGET("/data").respond("pig");
    expect(scope.data).toBe("pig");
  });

});

And this is the error I get in the shell:

INFO [watcher]: Changed file "/home/myApp/test/unit/controller/cDashboard.js".
Chrome 26.0 (Linux) cDashboard should get 'pig' from '/data' FAILED
    Error: No pending request to flush !
        at Error (<anonymous>)
        at Function.$httpBackend.flush (/home/myApp/test/lib/angular/angular-mocks.js:1171:34)
        at null.<anonymous> (/home/myApp/test/unit/controller/cDashboard.js:15:18)
Chrome 26.0 (Linux): Executed 1 of 1 (1 FAILED) (0.326 secs / 0.008 secs)
like image 409
Sir Robert Avatar asked May 07 '13 20:05

Sir Robert


1 Answers

There are a couple problems in your test code:

  1. The controller is created before the httpMock is configured to respond with pig. The expectGet call should happen before instantiating the controller.
  2. The httpMock needs to flush the request
  3. The httMock.when is unnecessary so long as you have the expectGet

Working example: http://plnkr.co/edit/lUkDMrsy1KJNai3ndtng?p=preview

describe('cDashboard', function(){
  var scope, controllerService, httpMock;

  beforeEach(inject(function ($rootScope, $controller, $httpBackend) {
    scope = $rootScope.$new();
    controllerService = $controller;
    httpMock = $httpBackend;
  }));

  it("should get 'pig' from '/data'", function () {
    httpMock.expectGET("/data").respond("pig");
    ctrl = controllerService('cDashboard', {$scope: scope});
    httpMock.flush();
    expect(scope.data).toBe("pig");
  });
});
like image 129
Matt York Avatar answered Sep 30 '22 01:09

Matt York