Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make $httpBackend ignore any requests made to server

I have the following controller (notice that at instantiation time I make an explicit call to $scope.getNotifications()):

bla.controller("myctrl", [
    "$scope", "$http", "configs", function ($scope, $http, configs) {

        $scope.getNotifications = function () {
            $http.get("bla/blabla").success(function (data) {

            });
        };

        $scope.removeNotification = function (notification) {
            var index = $scope.allNotifications.indexOf(notification);
            $scope.allNotifications.splice(index, 1);
        };

        $scope.getNotifications();
    }
]);

Then I make some unit tests (notice that the controller gets instantiated in the before each):

describe("blaController", function () {

    var scope, $httpBackend;

    beforeEach(module('bla'));

    beforeEach(inject(function ($controller, $rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        $controller('blaCtrl', { $scope: scope });
    }));

 afterEach(function(){
    //assert
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
 });

 it("should get all notifications from server when instantiated", function () {
    //arrange
    $httpBackend.expectGET("api/v1/notifications").respond(200, {});
    $httpBackend.flush();

    //act - done implicitly when controller is instantiated  
});

it("should store all notifications from server on the client when success call to server", function () {
    //arrange
    $httpBackend.whenGET("api/v1/notifications").respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
    $httpBackend.flush();

    //act - done implicitly when controller is instantiated

    //assert
    expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});

Everything is fine until now. All tests pass. But when I add a new test (see bellow) that does not require any HTTP calls it fails because in the afterEach() it verifies for expecations but there are no expectations set in the removeNotification(). This is the error message from karma: PhantomJS 1.9.7 (Windows 8) notificationCenterController removeNotification should remove the given notification from th e list FAILED Error: Unexpected request: GET api/v1/notifications No more request expected

it("should remove the given notification from the list", function () {
            //arrange
            var targetObj = { a: 2 };
            scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];

            //act
            scope.removeNotification(targetObj);

            //assert
            expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
        });

Most of my test do have http calls so placing the verify in the afterEach makes sense. I was wondering what other option do I have to avoid copy pasting the afterEach body in N-1 tests. Is there a way to tell $httpBackend to ignore any calls?

like image 291
Liviu Mandras Avatar asked Aug 27 '14 11:08

Liviu Mandras


2 Answers

you can wrap your test in describe block like below.

describe("blaController", function () {

    var scope, $httpBackend;

    beforeEach(module('bla'));

    beforeEach(inject(function ($controller, $rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        $controller('blaCtrl', { $scope: scope });
    }));

    describe('test http calls', function() {

        afterEach(function(){
            //assert
            $httpBackend.verifyNoOutstandingExpectation();
            $httpBackend.verifyNoOutstandingRequest();
        });

        it("should get all notifications from server when instantiated", function () {
            //arrange
            $httpBackend.expectGET("api/v1/notifications").respond(200, {});
            $httpBackend.flush();

            //act - done implicitly when controller is instantiated  
        });

        it("should store all notifications from server on the client when success call to server", function () {
        //arrange
            $httpBackend.whenGET("api/v1/notifications").respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
            $httpBackend.flush();

            //act - done implicitly when controller is instantiated

            //assert
            expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
        });

    }); 

    describe('other tests', function(){
        it("should remove the given notification from the list", function () {
            //arrange
            var targetObj = { a: 2 };
            scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];

            //act
            scope.removeNotification(targetObj);

            //assert
            expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
        });
    });
});
like image 165
Jeetendra Chauhan Avatar answered Nov 02 '22 19:11

Jeetendra Chauhan


You can spy on $http.get in a separate suite, that should work (pseudo-code below).

 describe("backend", function() { // your code from before });

 describe("non-backend", function () {

    var scope, $http;

    beforeEach(module('bla'));

    beforeEach(inject(function ($controller, $rootScope, _$http_) {
        scope = $rootScope.$new();
        $http = _$http_;
        spyOn($http, 'get').and.callFake(function() {
            return { some: 'data' };
        });
        $controller('blaCtrl', { $scope: scope, $http: $http });
    }));

    it("should remove the given notification from the list", function () {
        //arrange
        var targetObj = { a: 2 };
        scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];

        //act
        scope.removeNotification(targetObj);

        //assert
        expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
    });
});
like image 23
Lee Avatar answered Nov 02 '22 19:11

Lee