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.
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