はじめに
Chakra UIを使用したReactコンポーネントをテストする際、次のように毎回ChakraProviderを書く必要がありました。
render(
<ChakraProvider value={defaultSystem}>
<App />
</ChakraProvider>,
);
テストが増えると、すべてのテストに同じProviderを書くことになります。
この記事では、React Testing Libraryのwrapperを利用して、Providerの重複を減らす方法をメモしました。
環境
- React: 19
- Chakra UI: 3
- Vitest: 4
- React Testing Library: 16
変更前のテスト
変更前は、render()の中で毎回ChakraProviderを指定していました。
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
import App from "../App";
describe("App", () => {
test("タイトルがあること", async () => {
render(
<ChakraProvider value={defaultSystem}>
<App />
</ChakraProvider>,
);
await waitFor(() => {
screen.getByTestId("table");
});
const title = screen.getByTestId("title");
expect(title).toBeInTheDocument();
});
test("TODOが4つあること", async () => {
render(
<ChakraProvider value={defaultSystem}>
<App />
</ChakraProvider>,
);
// TODOの確認処理
});
});
React Testing Libraryのwrapperを使う
React Testing Libraryのrender()には、wrapperというオプションがあります。
render(<App />, {
wrapper: Provider,
});
wrapperへProviderを渡すと、内部的には次のような状態になります。
<Provider>
<App />
</Provider>
既存のProviderを利用する
すでにアプリケーション用のProviderがあるので、それを使用しました。
import { ChakraProvider, defaultSystem } from "@chakra-ui/react";
import {
ColorModeProvider,
type ColorModeProviderProps,
} from "./color-mode";
export function Provider(props: ColorModeProviderProps) {
return (
<ChakraProvider value={defaultSystem}>
<ColorModeProvider {...props} />
</ChakraProvider>
);
}
このProviderには、次のProviderが含まれています。
ChakraProviderColorModeProvider
テストでも同じProviderを再利用することで、本番に近い環境でコンポーネントを表示できます。
Provider付きのrender処理を関数にまとめる
テストファイルの上部へ、Provider付きでAppを表示する関数を作成します。
import { describe, expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import App from "../App";
import { Provider } from "../components/ui/provider";
// 処理をまとめる。
const renderApp = () => {
return render(<App />, {
wrapper: Provider,
});
};
describe("App", () => {
test("タイトルがあること", async () => {
renderApp();
const title = await screen.findByTestId("title");
expect(title).toBeInTheDocument();
});
test("TODOが4つあること", async () => {
renderApp();
// TODOの確認処理
});
});
これで、それぞれのテストでは次の1行だけでAppを表示できます。
renderApp();
参考
ありがとうございました!