Testing redirections set via window location href with Jest
Sometimes, we get hit with the following error when running our tests:
not implemented: navigation
A usual situation in which this kind of error may happen is when window.location.href
is reassigned by the application code.
If this doesn't ring a bell, think of this scenario: when a user clicks a button in your app, they might either be redirected to another view within the same app — where only window.history
is manipulated — or they might be redirected to an external page. It's when the app sends the user to an external page by changing the value of window.location.href
that you'll see the error mentioned at the beginning of this post.
The simplest way to avoid this problem is by drawing a clear boundary between the behavior that's under the control of your app and the behavior that's the browser's responsibility (fetching another document when a new value is assigned to window.location.href
).
Boundary set by the Window Service
You can create this boundary by setting up a service, which I like to call window service since it can also include other methods that solve other issues similar to the href
reassignment. Here's how I specify it:
// src/services/window.test.js
describe('Window Service', () => {
it('should set window location href', () => {
const { origin } = window.location;
const newUrl = `${origin}/#my-custom-hash`;
windowService.setHref(newUrl);
expect(window.location.href).toEqual(newUrl);
});
});
The goal of this suite is to make sure that window.location.href
is actually updated by the browser when I set it using the setHref
method. To avoid the not-implemented-navigation issue, we set a value that doesn't trigger any navigation by the browser: /#my-custom-hash
.
// src/services/window.js
const _public = {};
_public.setHref = href => {
window.location.href = href;
}
export default _public;
Now that we've ensured that calling windowService.setHref
gives us the same result as directly assigning a value to window.location.href
, we can replace direct assignments with the setHref
method in our implementation and mock this method in our tests:
describe('Conditional Button', () => {
beforeEach(() => {
windowService.setHref = jest.fn();
});
it('should redirect to help page if user does not satisfy some condition', () => {
render(<ConditionalButton />);
await screen.getByRole('button', { name: 'Go' });
expect(windowService.setHref).toHaveBeenCalledWith(
'https://some.support.page'
);
});
});
If this tip helped you successfully test redirection to an external page, you'll probably like knowing how to mock search params in React component tests.