Tanstack Routerを絡めたコンポーネントのUnitテストの覚え書き
概要
コンポーネントのUnitテストを行う際に、Tanstack Routerが絡んでくるコンポーネントがあります。
いくつかハマりどころがあったのでその際の対応をメモしました。
前提
- テストは
Jest
で行う"@testing-library/jest-dom": "^6.6.3"
"jest": "^29.7.0"
"jest-environment-jsdom": "^29.7.0"
"ts-jest": "^29.2.5"
- ルーティングはTanstack Routerを用い、一部のコンポーネントで
Link
やhooksを使っている"@tanstack/react-router": "^1.77.5"
RouterProviderでのラップ
Tanstack RouterはRouterProvider
でラップされていることが前提の挙動になります。
なので、Unitテスト時もその点を考慮する必要があります。
先行事例として以下がヒットしたので、そのまま流用します。
// src/__test__/DummyRouter.tsx
import {
Outlet,
RouterProvider,
createMemoryHistory,
createRootRoute,
createRoute,
createRouter,
} from "@tanstack/react-router";
import { type FC, type ReactNode } from "react";
export const DummyRouter: FC<{ component: () => ReactNode }> = ({
component,
}) => {
const rootRoute = createRootRoute({
component: Outlet,
});
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/",
component,
});
const routeTree = rootRoute.addChildren([indexRoute]);
const history = createMemoryHistory({ initialEntries: ["/"] });
const router = createRouter({ routeTree, history });
return <RouterProvider router={router} />;
};
さらに今回の環境ではMantineを使っていたので、そちらのProviderも複合しました。
他にもProviderが要求されるようなライブラリを使っている場合も同じような対応になるかと思います。
// src/__test__/Wrapper.tsx
import { MantineProvider } from "@mantine/core";
import { DummyRouter } from "./DummyRouter";
const Wrapper: React.JSXElementConstructor<{
children: React.ReactNode;
}> = ({ children }) => {
return (
<DummyRouter
component={() => <MantineProvider>{children}</MantineProvider>}
/>
);
};
export default Wrapper;
これで各Unitテストを行う際にrender
の第二引数にこのWrapperを渡すことで、テスト対象のコンポーネントが必要なProviderでラップされている状況を作ります。
// src/__test__/Hoge.test.tsx
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
// "@/"でエイリアスを通している前提。ここは各環境に合わせて適宜置き換える
import Hoge from "@/components/Hoge";
import Wrapper from "@/__test__/Wrapper";
describe("Hoge Unit Test", () => {
test("example", () => {
// Wrapperでラップした状態でテスト
render(<Hoge />, { wrapper: Wrapper });
expect(screen.getByText("hogehoge")).toBeInTheDocument();
});
});
Error: Not implemented: window.scrollTo
のエラー
「前提」のセクションで記載したバージョンでは、ここまでの対応だとUnitテストは実行されますが、最中にエラーが発生していました。
※エラーは発生するが、Unitテストの成否には影響がない状態
Error: Not implemented: window.scrollTo
どうやらTanstack Routerの内部でwindow.scrollTo
を使用しているようですが、Unitテスト環境下では使用できないためエラーになっているようです。
Tanstack Router側のIssueがあり、そこで解決策が明示されていました。
解決先は下記の記事にありました。
これをそのまま流用します。
// <root>/testSetup.ts
// jest実行時にTanstack Router内でwindow.scrollToを要求されるが、unitテストには無関係なのでnoop化する
const noop = () => {};
Object.defineProperty(window, "scrollTo", { value: noop, writable: true });
+ "setupFiles": ["./testSetup.ts"]
これでエラーが発生しなくなりました。
まとめ
今回はTanstack Routerを用いた環境下でのコンポーネントのUnitテスト時のハマりどころをまとめました。
ルーティングのライブラリの中だとかなりメジャーな方なので、テスト時には皆さん同じような箇所でつまづいているのではないかと思います。
今回の記事が役立ちましたら幸いです。
Discussion