How to test components using new react router hooks?

I looked at the tests for hooks in the react-router repo and it looks like you have to wrap your component inside a MemoryRouter and Route. I ended up doing something like this to make my tests work:

import {Route, MemoryRouter} from 'react-router-dom';

...

const renderWithRouter = ({children}) => (
  render(
    <MemoryRouter initialEntries={['blogs/1']}>
      <Route path='blogs/:blogId'>
        {children}
      </Route>
    </MemoryRouter>
  )
)

Hope that helps!


Edit: The proper way of doing this the way described in Catalina Astengo's answer as it uses the real router functionality with just the history/routing state mocked rather than mocking the entire hook.

The way I ended up solving it was by mocking the hooks in my tests using jest.mock:

// TeamPage.test.js
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
  useParams: () => ({
    companyId: 'company-id1',
    teamId: 'team-id1',
  }),
  useRouteMatch: () => ({ url: '/company/company-id1/team/team-id1' }),
}));

I use jest.requireActual to use the real parts of react-router-dom for everything except the hooks I'm interested in mocking.


If you're using react-testing-library for testing, you can get this mock to work like so.

jest.mock('react-router-dom', () => ({
    ...jest.requireActual('react-router-dom'),
    useLocation: () => ({ state: { email: '[email protected]' } }),
}));

export const withReduxNRouter = (
    ui,
    { store = createStore(rootReducer, {}) } = {},
    {
    route = '/',
    history = createMemoryHistory({ initialEntries: [ route ] }),
    } = {}
) => {
    return {
    ...render(
        <Provider store={store}>
        <Router history={history}>{ui}</Router>
        </Provider>
    ),
    history,
    store,
    };
};

You should have mocked react-router-dom before it has been used to render your component. I'm exploring ways to make this reusable


In your component use hooks as below

import {useLocation} from 'react-router';

const location = useLocation()

In your test spy on reactRouter Object as below

import routeData from 'react-router';

const mockLocation = {
  pathname: '/welcome',
  hash: '',
  search: '',
  state: ''
}
beforeEach(() => {
  jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation)
});

Tags:

React Router