Jest: Testing window.location.reload

If you use TypeScript with Jest:

Idea

  1. Create a copy and then delete window's location property.
  2. Now set location property with reload function mocked.
  3. Set the original value back when test completes.

Code: TypeScript 3.x and below

const location: Location = window.location;
delete window.location;
window.location = {
    ...location,
    reload: jest.fn()
};

// <code to test>
// <code to test>
// <code to test>

expect(window.location.reload).toHaveBeenCalledTimes(1);
jest.restoreAllMocks();
window.location = location;

Code: TypeScript 4+

TypeScript 4 has stricter checks (which is a good thing), so I am not really sure if there's a way to do this other than to suppress the error using @ts-ignore or @ts-expect-error.

WARNING: Suppressing TypeScript validations can be 🔴dangerous🔴.

const location: Location = window.location;

// WARNING:
//     @ts-ignore and @ts-expect-error suppress TypeScript validations by ignoring errors.
//     Suppressing TypeScript validations can be 🔴dangerous🔴.

// @ts-ignore
delete window.location;

window.location = {
    ...location,
    reload: jest.fn()
};

// <code to test>
// <code to test>
// <code to test>

expect(window.location.reload).toHaveBeenCalledTimes(1);
jest.restoreAllMocks();
window.location = location;

You can also simplify Murtaza Hussain's solution to

  describe('refreshPage', () => {
    const { reload } = window.location;

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

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

    it('reloads the window', () => {
      refreshPage();
      expect(window.location.reload).toHaveBeenCalled();
    });
  });

Updated Answer (November 2021)

Package: "jest": "^26.6.0" "@testing-library/jest-dom": "^5.11.4"

Build: create-react-app 4

describe("test window location's reload function", () => {
  const original = window.location;

  const reloadFn = () => {
    window.location.reload(true);
  };

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

  afterAll(() => {
    Object.defineProperty(window, 'location', { configurable: true, value: original });
  });

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

  it('calls reload function', () => {
    reloadFn(); // as defined above..
    expect(window.location.reload).toHaveBeenCalled();
  });
});

Note: Updated answer because the the old answer wasn't supported with latest jest version used in CRA.


Old answer

Here’s the solution but refactored for better organization:

describe('test window location\'s reload function', () => {
  const { reload } = window.location;

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

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

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

  it('calls reload function', () => {
    reloadFn(); // as defined above..
    expect(window.location.reload).toHaveBeenCalled();
  });
});

Thanks :)