Reputation: 399
In one of my controllers I have a location.reload()
(For those who wants to know why, My login page does not load the entire app before the user logs in to reduce threshold on the server)
When I test the controller (using jasmine html for the ui), it actually reloads the test in an infinite loop.
My questions is this:
How do I avoid the location.reload() from loading the test itself, and how do I even check whether it has been called? can I mock it somehow?
Here's the code for the controller:
(function() {
'use strict';
angular
.module('app.ctrls')
.controller('LoginController', LoginController);
LoginController.$inject = [ '$scope', 'AuthService' ];
function LoginController($scope, AuthService)
{
console.log('LoginController');
$scope.credantials = {
email: '',
password: '',
remember: false
}
$scope.login = function(credantials)
{
AuthService.login(credantials.email, credantials.password, credantials.remember || false).success(function(response) {
console.log(response);
if (response.email !== null)
{
$scope.logged = true;
console.log('login successful');
location.reload();
}
else
{
$scope.logged = false;
$scope.error = true;
}
}).error(function() {
console.log('failed to login');
});
};
}
})();
Here's the spec:
describe("successfully logged in", function() {
it("should reload the page", function() {
this.scope.credantials = { email: '[email protected]', password: '123', remember: false };
this.$httpBackend.expectPOST('/auth/login', this.scope.credantials).respond({first_name: "Bakayaru", email: "[email protected]"});
this.$httpBackend.whenGET('/tpls/home.html').respond(200);
this.scope.login(this.scope.credantials);
this.$httpBackend.flush();
expect(this.scope).toBeDefined();
expect(this.scope.logged).toBeTruthy();
/* -------> TEST that location.reload() has been called HERE <--------- */
});
});
Upvotes: 4
Views: 10455
Reputation: 912
You can mock $window in your test like this:
describe('service', function () {
var $window;
beforeEach(module('core', function ($provide) {
$window = {
location:{
reload: jasmine.createSpy()
}
};
$provide.value('$window', $window);
}));
});
This way it will "override" the default behaviour of $window.
Upvotes: 2
Reputation: 399
I realized that just like Unit Tests in PHP for example, when the code has file_get_content
for example, you have to mock it yourself, and not test it.
The location.reload
is a browser component and therefor must be mocked for my code to become testable.
Therefore I have created a BrowserService
:
(function() {
'use strict';
angular
.module('rushcore.services')
.factory('BrowserService', BrowserService);
function BrowserService()
{
console.log('BrowserService');
return {
reload: function() {
location.reload();
}
};
}
})();
And in the test I mocked it and injected it.
var BrowserServiceMock = { reload: function(){ console.log("reloaded"); } };
I then spied on it:
var reload = spyOn(BrowserServiceMock, 'reload');
And finally made sure it was called:
expect(reload).toHaveBeenCalled();
Upvotes: 1
Reputation: 111
I am not sure what you mean by "not loading itself" but anyways it is possible to mock the .reload() in tests. I did it in my App by first of all using Angular service $window.location instead of native javascript location in my App like this after injection $window as dependency to my controller:
$window.location.reload();
Then in the spec file I have the following (with one example test case using the mocked reload):
describe('Controller: MyCtrl', function () {
// load the controller's module
beforeEach(module('myApp'));
var MyCtrl,
scope,
mockBackend,
window;
beforeEach(function(){
inject(function(_$httpBackend_, $controller, $rootScope, $window) {
scope = $rootScope.$new();
mockBackend = _$httpBackend_;
window = $window;
spyOn(window.location, 'reload');
myCtrl = $controller('MyCtrl', {
$scope: scope,
$window: window
});
});
});
it('logout should fail if $window.reload() is called on unsuccessful logout call', function(){
scope.logout();
mockBackend.expectGET('/rest/session/logout').respond(404);
mockBackend.flush();
expect(window.location.reload.calls.count()).toEqual(0);
mockBackend.verifyNoOutstandingExpectation();
mockBackend.verifyNoOutstandingRequest();
});
});
This is a bit differently structured to your spec file, but I hope this example clarifies how to mock $window object and use spies on it.
Upvotes: 4