I've got the following service:
angular.module("services")
.factory("whatever", function($window) {
return {
redirect: function() {
$window.location.replace("http://www.whatever.com");
}
};
});
How to mock $window object in unit test to prevent reloading the page when running tests?
I tried using
spyOn($window.location, 'replace').andReturn(true);
, but it didn't work (still got "Some of your tests did a full page reload!" error) and
$provide.value('$window', {location: {replace: jasmine.createSpy()}})
, but I was getting an error (Error: [ng:areq] Argument 'fn' is not a function, got Object) with stack trace pointing only to angular own source, so it wasn't very helpful...
In Chrome (didn't test inother browsers), location.replace is readonly so spyOn wasn't able to replace it.
$provide.value should work. Something must be wrong somewhere in your code.
Here is a working unit test
describe('whatever', function() {
var $window, whatever;
beforeEach(module('services'));
beforeEach(function() {
$window = {location: { replace: jasmine.createSpy()} };
module(function($provide) {
$provide.value('$window', $window);
});
inject(function($injector) {
whatever = $injector.get('whatever');
});
});
it('replace redirects to http://www.whatever.com', function() {
whatever.redirect();
expect($window.location.replace).toHaveBeenCalledWith('http://www.whatever.com');
});
});
I'm going with an easier but perhaps less elegant solution. I'm writing a wrapper for $window.location, which I can then mock. Relating that to your code, I'd be mocking the whatever.redirect function, rather than mocking $window (I'm assuming here that your real function is more complex).
So I'd end up with:
angular.module("services")
.factory("whatever", function($window) {
return {
do_stuff_that_redirects: function() {
lots of code;
this.redirect("http://www.whatever.com");
maybe_more_code_maybe_not;
},
redirect: function(url) {
$window.location.replace(url);
}
};
});
I can then directly mock the redirect method, and just trust that since it's only one line of code it can't really go wrong.
spyOn(whatever, 'redirect').andCallFake(function(){});
expect(whatever.redirect).toHaveBeenCalledWith('http:/my.expected/url');
This is sufficient for my purposes, and lets me validate the url called.
I'll offer another approach that might work for you. I faced the same problem while unit testing a controller 'action' that ultimately redirects the user (full-page-load, but to a different page in the larger website/application). To give some context, the controller fires off an AJAX request, and if the response is OK, it will redirect the user to a different page via $window.location.replace():
$http.post('save', data)
.success(function(responseData, status, headers, config) {
if(responseData.redirect) {
$window.location.replace(responseData.redirect);
}
})
.error(function(responseData, status, headers, config) {
console.error("ERROR while trying to create the Event!!");
});
The test for this controller function caused the same "Some of your tests did a full page reload!" error. So I added the following to the beforeEach() function for the controller spec, to mock out the $window service:
mockWindow = { location: { replace: function(url) { console.log('redirecting to: ' + url); } } };
eventCtrl = $controller('EventCtrl', { $scope: scope, $window: mockWindow });
Of course, this solution prevents me from (cleanly) verifying that the replace function was called with an expected argument, but I don't really care about that right now.... Hope that helps.
I think what you want is to use the $location service, rather then calling $window.location. There is also a whole page explaining this feature here: http://docs.angularjs.org/guide/dev_guide.services.$location.
Using this, it should be fairly simple to use a stubbed version of the $location service in you tests.
$location.path('/someNewPath');
$location.replace(); // or you can chain these as: $location.path('/someNewPath').replace();
来源:https://stackoverflow.com/questions/20252382/how-to-mock-window-location-replace-in-angularjs-unit-test