Skip to content

React Router v7のルートモジュールコンポーネントをテストする

createRoutesStub でモック用のルーターを作ってテストをする。

import { createRoutesStub } from "react-router";
import { Sidebar } from ".";
import { render } from "@testing-library/react";
const Stub = createRoutesStub([
{
path: "/orgs/:orgId",
Component: Sidebar,
},
]);
const { container } = render(<Stub initialEntries={["/orgs/test-org"]} />);
expect(container.childNodes).toMatchSnapshot();

ここではルートモジュールのコンポーネントで loaderaction が必要な場合を説明する。loaderaction それ自体のテストはReact Router v7でルートモジュールのloaderやactionをテストするに書いた。

createRoutesStub に渡す routes 引数は、v7.1.1 時点では以下の定義となっており、loaderData などといった Route.LoaderArgs プロパティを渡せない。

Component?: React.ComponentType | null;

この問題はcreateRoutesStub fails type checkingで挙がっているけれど、今の時点では回避策として useLoaderData フックを使うといいらしい。

import Merchants, { loader } from "./merchants.js";
import { createRoutesStub, useLoaderData } from "react-router";
import { render, waitFor } from "@testing-library/react";
const Stub = createRoutesStub([
{
path: "/orgs/:orgId/merchants",
HydrateFallback: () => null,
Component: (): JSX.Element => {
const loaderData = useLoaderData<typeof loader>();
// @ts-expect-error
return <Merchants loaderData={loaderData} />;
},
loader(): Awaited<ReturnType<typeof loader>> {
return { ... };
},
},
]);
const { container, getByText } = render(
<Stub initialEntries={["/orgs/test-org/merchants"]} />,
);
await waitFor(() => {
expect(getByText("Shop1")).toBeVisible();
expect(container).toMatchSnapshot();
});

Vitestで toBeVisible などのDOMマッチャーが使えない場合はVitestで@testing-libraryのDOMマッチャーを使うを参考に設定する。