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?
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 }]);
});
});
});
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 }]);
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With