How to mock window.location methods


Mock method

You may encounter a scenario where you need to mock window.location methods in your Jest tests:

it('mocks and calls window.location.reload', () => {
  window.location.reload = jest.fn();
  window.location.reload();
  expect(window.location.reload).toHaveBeenCalled();
});

However, when you run the test, it fails.

Spy on method

Spying on the method does make the test pass:

it('mocks and calls window.location.reload', () => {
  jest.spyOn(window.location, 'reload');
  window.location.reload();
  expect(window.location.reload).toHaveBeenCalled();
});

But you’ll still get the error in your console:

console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
  Error: Not implemented: navigation (except hash changes)

This is because jsdom is trying to make the method behave like it would in a browser.

Mock method (2nd attempt)

To clear the error, the window.location.reload property needs to be made configurable before reassigning it to a mock function:

it('mocks and calls window.location.reload', () => {
  Object.defineProperty(window.location, 'reload', {
    configurable: true,
  });
  window.location.reload = jest.fn();
  window.location.reload();
  expect(window.location.reload).toHaveBeenCalled();
});

Now when you run the test, it should pass.

Final solution

Here’s the solution but refactored for better organization:

describe('window.location.reload', () => {
  // reference of the original method
  const { reload } = window.location;

  beforeAll(() => {
    Object.defineProperty(window.location, 'reload', {
      configurable: true,
    });
    window.location.reload = jest.fn();
  });

  afterAll(() => {
    window.location.reload = reload;
  });

  it('mocks method', () => {
    expect(jest.isMockFunction(window.location.reload)).toBe(true);
  });

  it('calls method', () => {
    window.location.reload();
    expect(window.location.reload).toHaveBeenCalled();
  });
});

You can check out the Gist that inspired this post.