Mocking React Router’s match object in component unit tests

Recently our UI team has switched from Enzyme to Kent Dodd’s Testing Library for a much improved, simplified experience in testing JavaScript and React components.

The issue
We have a growing number of applications which rely upon React Router to to handle client-side routing, and a good number of “container” components are dependent upon a URL parameter value for making network requests.

When testing these components with Testing Library / Jest, we need a way to mock routes and route parameter values via React Router’s match object in our component tests.

Setup
In one application, the following UI interface route is structured as http://some-url-here/project/project-id-goes-here:

Image for post
Image for post
A url parameter in current route

In a React container component which drives the UI above, the component’s network request is dependent upon the id from match.params (which is passed as a prop to the component when wrapped with React Router’s withRouter()).

So, the component grabs a project id value, then passes the value to our GraphQL API to retrieve additional project data for the component.

https://gist.github.com/adamjarling/a354755f5597ded173e83b10aaf68301

Testing the component
Everything works as expected in the live app, but when unit testing components structured as above with Testing Library’s render() function given example recipes, they were failing.

Testing Library’s documentation provides some helpful recipes for utility functions and examples of how to insert the history object into a React component via renderWithRouter(). This helps test scenarios like clicking on a link and testing the app renders the new route, etc.

https://gist.github.com/adamjarling/9ac59f3f8984c4c19d34018ee8a0401c

When we initially used this approach, we supplied a starting route value, ie. { route: "/project/ABC123" }, and history gets updated as expected, however React Router’s match object always returned an empty object{}. The value “ABC123” was not making its way into our components being tested.

Solution
Thanks to a Spectrum thread featuring some good advice here, the solution for mocking React Routers’ match object was relatively simple; to include a <Route /> inside <Router /> and setting the Route's path attribute to the same as in our application. We’re now successfully able to mock match.params in tests.

// Helper function
export function renderWithRouterMatch( ui,
{
path = “/”, // ie. "/project/:id"
route = “/”, // ie. "/project/ABC123"
history = createMemoryHistory({ initialEntries: [route] })
} = {}) {
return {
…render(
<Router history={history}>
<Route path={path} component={ui} />
</Router>
)
};
}

Below is gist of our utility helper function sample implementation that seems to be working reasonably well. Hopefully it helps anyone else who has container components structured in a similar fashion.

https://gist.github.com/adamjarling/5b5f607e45d9de47f9d18423697b2535

Written by

Senior Front-End Developer/Manager — Northwestern University Libraries Repository and Digital Curation

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store