React Native と jest を使う際の react-navigation のテスト実装2022/01/05

React Native と jest を使う際の react-navigation のテスト実装

React Native と jest でテストを実装する際の、react-navigation のテストの書き方の紹介です。

各コンポーネント単位でテストするように実装していれば、react-navigation を使わなくてもそれぞれのコンポーネントに対して描写やロジックのテストを書くことが可能です。

screen をまるごと描写テストしたい時、ボタンタップ時のスクリーン移動のテスト、アプリ起動時のホーム画面のマウントのテストなどが必要な場合があります。 その場合、react-navigationuseNavigationuseRoute が必要になるため、テストで動かせるようにする必要があります。

概要

  • 参考リンク
  • エラーになる場所
  • ナビゲーションクリエイターで挟む
  • screen の遷移をテストする
  • useRoute で遷移時に受け取るパラメータをモックする
  • test-utils などに追加するか

参考リンク

https://callstack.github.io/react-native-testing-library/docs/react-navigation

https://medium.com/@dariaruckaolszaska/testing-your-react-navigation-5-hooks-b8b8f745e5b6

エラーになる場所

useNavigation や useRoute を使う場所にてエラーになります。

画面遷移の際にパラメータとして受け取るデータなどを利用している場合も、パラメータがないためエラーになります。

ナビゲーションクリエイターで挟む

基本的には、実際のアプリの実装と同じようにするため NavigationContainer でナビゲーションを作ります。stack であれば createStackNavigator を使って Stack ナビゲーションを設定します。

こうすることで useNavigation や useRoute が動作できるようになります。

たとえば以下は useNavigation を使っている HomeScreen のテストのために、Stack ナビゲーションを用意しています。

import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";

const Stack = createStackNavigator();

  describe("HomeScreen", () => {
    it(`初期データ取得処理 fetchMessage を実行する`, () => {
      const params = {};
      render(
          <NavigationContainer>            <Stack.Navigator>              <Stack.Screen                name="HomeScreen"                component={HomeScreen}                initialParams={params}              />            </Stack.Navigator>          </NavigationContainer>      );
    });
  });

screen の遷移をテストする

useNavigation のページ遷移をテストしたい場合は、必要になるスクリーンを Route として設定しておけば、テストが可能です。

以下は HomeScreen からボタンをタップして DisplayScreen に遷移することをテストする例です。 Route の名前は実装で使っているものと同じでないと、遷移の際に移動先が見つからないエラーとなります。実装と同じ name を各スクリーンに設定しましょう。

    it(`ボタンを押すとupdateMessageを実行して、display screen に遷移する`, async () => {
      const params = {};
      const component = render(
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen                name="Home"                component={HomeScreen}                initialParams={params}              />              <Stack.Screen                name="Display"                component={DisplayScreen}                initialParams={params}              />            </Stack.Navigator>
          </NavigationContainer>
      );
      const { findByText, findByTestId } = component;
      const button = await findByTestId("navButton");
      fireEvent(button, "press");

      const nextPage = await findByTestId("displayScreen");
      expect(nextPage).toBeTruthy();
    });
  });

useRoute で遷移時に受け取るパラメータをモックする

スクリーンによっては遷移の際に前の画面から受け取ったパラメータを使用する画面もあります。

その場合はスクリーンに initialParams としてテストデータを設定することで、仮のものとして受け取ることができます。

以下はホーム画面からパラメータを受け取って表示する DisplayScreen の表示テストです。

    it(`display screen を表示する`, async () => {
      const params = {
        text: "hello",
      };
      const component = render(
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen name="Home" component={HomeScreen} />
              <Stack.Screen
                name="Display"
                component={DisplayScreen}
                initialParams={params}              />
            </Stack.Navigator>
          </NavigationContainer>
      );
    });

test-utils などに追加するか

test-utils に NavigationContainer を設定したカスタムレンダーを用意するのも便利です。しかし、ナビゲーションを設定するとヘッダーやボトムタブなどが描写されます。

コンポーネントのテストなどではそれは不要なので、個人的には必要な pages のテストやアプリマウント時のテストなど、必要となるテストケースの中で都度ナビゲーションを設定するようにしています。

おわりに

screen 単位のテストについてはそもそも実装しないという方針もあります。 各コンポーネント単位でテストができていればいいですし、ロジックなどはなるべく切り出して screen に含まないように設計するのが望ましいです。

表示のテストやアプリマウントのテストが必要な場合、今回紹介したよう方法でテストを書くのはお手軽でですが、Detox などを使ってE2Eテストで実装するのもおすすめです。 準備などは必要ですが、こちらも便利なので機会があれば設定して置けるとテストがもっと便利になります。

  • このエントリーをはてなブックマークに追加
prev
next