如何使用 React Router v6 和测试库测试路由逻辑?

lzl*_*31x 9 reactjs react-router react-router-dom react-testing-library

我按照本教程从 React Router v5 迁移到 v6 。我想用react-testing-library来测试它,但是我的旧单元测试(使用本文档中的模式)停止工作。

我的 React Router v6 应用程序是这样的

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>
    );
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它使用RouterProvider而不是Switch/ Route(所以我很困惑,这个SO 问题说它使用的是 React Router v6,但它看起来很不同。)。

测试库官方文档中的代码也没有使用RouterProvider

我想测试一些路由逻辑,如以下伪代码:

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
Run Code Online (Sandbox Code Playgroud)

我怎样才能创建这样renderWithRouter函数?RouterProvider请注意,当我使用 React Router v5 时,这对我有用,但在迁移到 v6 后,它停止工作。renderWithRouter

我当前的依赖版本:

  • “反应”:“^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",

我试过这个

test("click post goes to /post/:postId", async () => {
    render(
        <MemoryRouter initialEntries={["/posts"]}>
            <App />
        </MemoryRouter>,
    );
    // ...
});
Run Code Online (Sandbox Code Playgroud)

但我得到了错误

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 />
Run Code Online (Sandbox Code Playgroud)

Dre*_*ese 15

如果您想使用新的数据路由器来测试整个路由配置react-router-dom@6.4,那么我建议对代码进行一些重构,以允许能够存根进行MemoryRouter任何单元测试。

自行声明路由配置并导出。

const routesConfig = [
  {
    path: "/",
    element: (
      <>
        <SiteHeader />
        <Outlet />
      </>
    ),
    errorElement: <NotFound />,
    children: [
      { path: "/", element: <Home /> },
      { path: "/posts", element: <Posts /> },
      { path: "/post/:postId", element: <PostPage /> },
    ],
  },
];

export default routesConfig;
Run Code Online (Sandbox Code Playgroud)

在应用程序代码中导入routesConfig并实例化BrowserRouter应用程序使用的。

import {
  RouterProvider,
  createBrowserRouter,
} from "react-router-dom";
import routesConfig from '../routes';

const router = createBrowserRouter(routesConfig);

function App() {
  return (
    <div className="app">
      <RouterProvider router={router} />
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

对于单元测试,导入routesConfig并实例化MemoryRouter.

import {
  RouterProvider,
  createMemoryRouter,
} from "react-router-dom";
import { render, waitFor } from "@testing-library/react";
import routesConfig from '../routes';

...

test("click post goes to /post/:postId", async () => {
  const router = createMemoryRouter(routesConfig, {
    initialEntries: ["/posts"],
  });

  render(<RouterProvider router={router} />);

  // make assertions, await changes, etc...
});
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,https://testing-library.com/docs/example-react-router 可能应该对此进行更新。:D (3认同)