import { render, screen, waitFor } from '@testing-library/react';
import React from "react";
import { createMemoryRouter, RouterProvider, Outlet, createBrowserRouter } from 'react-router-dom';
const Layout = () => (
<div>
<header>Header</header>
<main>
<Outlet />
</main>
<footer>Footer</footer>
</div>
);
const routes = [
{
path: '/',
element: <Layout />,
children: [
{ path: '/', element: <>home</> },
{ path: 'about', element: <>about</> },
],
},
];
const router = createBrowserRouter(routes);
function App() {
return <RouterProvider router={router} />;
}
describe("sample code ", () => {
it("test home", async () => {
const router1 = createMemoryRouter(routes, { initialEntries: ['/about'] })
render(
<RouterProvider router={router1} />
);
expect(screen.getByText(/header/i)).toBeInTheDocument();
await waitFor(() => expect(screen.getByText(/about/i)).toBeInTheDocument());
expect(screen.getByText(/footer/i)).toBeInTheDocument();
})
})
I'm currently testing routes and nested routes using initial entries in React Testing Library (RTL). However, I'm encountering an issue where the Outlet component isn't functioning as expected in my tests, even though it works perfectly in the actual application.
I was initially able to reproduce the testing issue you described. The same code you have here works perfectly well in React-Router-DOM 6, so something non-trivial, but very subtle, changed in the major version update from v6 to v7.
I checked:
It was in the migration guide where they discuss in better detail the deprecations and changes to be made from v6 to v7. Specifically the "Update DOM-specific imports" section at the end that describes where RouterProvider
is exported from in the repo.
👉 Update DOM-specific imports
RouterProvider
andHydratedRouter
come from a deep import because they depend on "react-dom":-import { RouterProvider } from "react-router-dom"; +import { RouterProvider } from "react-router/dom";
Note you should use a top-level import for non-DOM contexts, such as Jest tests:
-import { RouterProvider } from "react-router-dom"; +import { RouterProvider } from "react-router";
Congratulations, you're now on v7!
In your unit test code, import the router components from react-router
instead of react-router-dom
.
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import React from "react";
import {
createMemoryRouter,
RouterProvider,
Outlet,
createBrowserRouter,
} from "react-router"; // <-- Use main React-Router package!
const Layout = () => (
<div>
<header>Header</header>
<main>
<Outlet />
</main>
<footer>Footer</footer>
</div>
);
const routes = [
{
path: "/",
element: <Layout />,
children: [
{ path: "/", element: <>home</> },
{ path: "about", element: <div>about</div> },
],
},
];
const router = createBrowserRouter(routes);
function App() {
return <RouterProvider router={router} />;
}
describe("sample code ", () => {
it("test home", async () => {
const router1 = createMemoryRouter(routes, { initialEntries: ["/about"] });
render(<RouterProvider router={router1} />);
expect(screen.getByText(/header/i)).toBeInTheDocument();
expect(screen.getByText(/about/i)).toBeInTheDocument();
expect(screen.getByText(/footer/i)).toBeInTheDocument();
});
});
Even though @remix/react-router
re-exports all of react-router-dom
, this doesn't include the RouterProvider
which is located in another repo package. Using react-router-dom
alone doesn't get you the correct imports.