1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React Testing Library カスタムレンダーの仕組み

1
Posted at

背景

Chakra UI の Provider(ChakraProvider)を利用しているプロジェクトで、React Testing Library のテストを書いていたら、テスト環境では Provider が存在せずコンポーネントが正しく動かない問題にぶつかった

毎回テストファイルで ChakraProvider を書くのは DRY に反するので、カスタムレンダー(Custom Render)を作って解決した

カスタムレンダーとは

render(<Component />) と書くだけで、裏で自動的に Provider が全部付いてくるようにするラッパー関数

本番では App.tsx が Provider 群で全体を囲んでいるが、テストでは App を経由せず直接コンポーネントをレンダリングする。そのため Provider が存在しない状態になり、テーマや i18n が動かない。カスタムレンダーは、テスト用にも同じ Provider で囲む仕組みを提供する

実装の全体像

AllTheProviders コンポーネント

const AllTheProviders = ({children}: {children: React.ReactNode}) => {
  return (
    <ThemeProvider>
      <TranslationProvider>
        {children}
      </TranslationProvider>
    </ThemeProvider>
  )
}
  • ({children}: {children: React.ReactNode}) は JS の分割代入と TypeScript の型注釈を同時にやっている
    • {children} → props オブジェクトから children プロパティだけ取り出す(分割代入)
    • : {children: React.ReactNode} → TypeScript の型注釈。React.ReactNode は React が描画できるもの全般の型(文字列、数値、JSX、配列、null など)
  • children とは、コンポーネントのタグの中に挟んだものが自動的に渡される仕組み
<AllTheProviders>
  <MyComponent />   ← これがchildren
</AllTheProviders>

customRender 関数

const customRender = (
  ui: ReactElement,
  options?: Omit<RenderOptions, 'wrapper'>,
) => render(ui, {wrapper: AllTheProviders, ...options})

引数を一つずつ分解する:

  • ui: ReactElement → テストしたい JSX コンポーネント
  • options?: Omit<RenderOptions, 'wrapper'> の分解:
    • ? → 省略可能(オプショナルパラメータ)
    • RenderOptions → RTL の render が受け取るオプションの型
    • Omit<RenderOptions, 'wrapper'> → RenderOptions から wrapper プロパティだけ除外した型。カスタムレンダーは wrapper: AllTheProviders を強制する設計なので、外からの上書きを型レベルで禁止している
  • {wrapper: AllTheProviders, ...options} → wrapper は常に AllTheProviders を使い、その他のオプションはスプレッド構文で展開して渡す

エクスポートのパターン

export * from '@testing-library/react'   // 全APIをそのまま再エクスポート
export {customRender as render}          // renderだけカスタム版で上書き

これにより、テスト側の import 元を @testing-library/reacttest-utils に変えるだけで、Provider が自動的に付いてくる

まとめ

  • カスタムレンダーは「テストで render(<Component />) と書くだけで Provider が全部付いてくるラッパー関数」
  • Omit<RenderOptions, 'wrapper'> で wrapper の上書きを型レベルで禁止するのがポイント
  • テスト側の import 元を test-utils に変えるだけで、Provider が自動的に付いてくる

感想

  • テスト環境との違いがよくわかったので結構良い調査だった

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?