chevron-left chevron-right

Testing location change in useEffect in React

Once I created a React component that was updating the app URL in useEffect based on some conditions. The logic was that whenever a user gets to the meetings list and none is selected yet, then by default a first item should be marked as selected. This information should be visible both in the UI (some special styles are applied then) and in the browser address bar (the id of a meeting should be a part of URL).


In my app I’m using react-router-dom and the useHistory hook. Looks at the code:

import { useHistory, useParams } from 'react-router-dom`;

export const MyComponent = ({ meetings }) => {
    const hsitory = useHistory();
    const { meetingId } = useParams();

    useEffect(() => {
        if (!meetingId) {
            history.push('meetings/' + meetings[0].id /* 1234 */);
    }, [meetingId, meetings]);

    return <div>MyComponent: {meetingId}</div>; 

In my tests I tried to do something like this:

it('adds the first meeting to URL', () => {


Obviously, the test was failing. Because this URL looks differently on first render. It looks like that: /meetings

I tried to use waitFor like here:

await waitFor(() => {

But it was giving false positives - it was not testing it properly.

Ultimately, I found a better solution, which is spying on history methods. Check the code below:

import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';

let history;

const renderComponent = () => {
    history = createMemoryHistory();

    render(<Router history={history}><MyComponent /></Router>);

it('tests location changes', () => {

    const pushSpy = jest.spyOn(history, 'push');


This way I was able to test the URL changes in a satisfying way.


I hope you find this post useful. It’s a kind of Things-I-Learnt (TIL) post. If you have any questions, do not hesitate to ask. Happy coding!