I migrated from React Router v5 to v6 following this tutorial. I want to test it with react-testing-library, but my old unit tests (using the pattern in this doc) stopped working.
My app with React Router v6 is like this
const router = createBrowserRouter([
{
path: "/",
element: (
<>
<SiteHeader />
<Outlet />
</>
),
errorElement: <NotFound />,
children: [
{ path: "/", element: <Home /> },
{ path: "/posts", element: <Posts /> },
{ path: "/post/:postId", element: <PostPage /> },
],
},
]);
function App() {
return (
<div className="app">
<RouterProvider router={router} />
</div>
);
}
As you can see, it's using RouterProvider
instead of Switch
/Route
(so I'm confused that this SO question says it's using React Router v6 but it looks so different.).
The code in official doc of testing-library is not using RouterProvider
either.
I want to test some routing logic like this pseudo code:
renderWithRouter(<App />, "/posts"); // loads /posts page initially
await user.click(screen.getByText("some post title")); // trigger click
expect(getUrl(location)).toEqual("/post/123"); // checks the URL changed correctly
How can I create a renderWithRouter
function like this with RouterProvider
? Note that this renderWithRouter
worked for me when I used React Router v5, but after migrating to v6, it stopped working.
My current dependency versions:
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-router-dom": "^6.4.3",
- "@testing-library/jest-dom": "^5.16.5",
- "@testing-library/react": "^13.4.0",
- "@testing-library/user-event": "^14.4.3",
I tried this
test("click post goes to /post/:postId", async () => {
render(
<MemoryRouter initialEntries={["/posts"]}>
<App />
</MemoryRouter>,
);
// ...
});
but I got error
You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
31 | test("click post goes to /post/:postId", async () => {
> 32 | render(
| ^
34 | <MemoryRouter initialEntries={["/posts"]}>
36 | <App />
Posts
component in aMemoryRouter
and testingPosts
behavior, as an example? – LedouxMemoryRouter
(see the end) – SelectivePost
component, then try rendering onlyPost
. Again, it depends on what you are trying to unit test. Sometimes some components need to be rendered within a routing context, so a router is necessary to provide the context. – Ledouxreact-testing-library
isn't the correct tool for the job of integration testing. For this look for something like puppeteer, selenium, cypress, etc. – Ledoux