React Native と jest を使う際の react-navigation のテスト実装
React Native と jest でテストを実装する際の、react-navigation
のテストの書き方の紹介です。
各コンポーネント単位でテストするように実装していれば、react-navigation
を使わなくてもそれぞれのコンポーネントに対して描写やロジックのテストを書くことが可能です。
screen をまるごと描写テストしたい時、ボタンタップ時のスクリーン移動のテスト、アプリ起動時のホーム画面のマウントのテストなどが必要な場合があります。
その場合、react-navigation
のuseNavigation
や useRoute
が必要になるため、テストで動かせるようにする必要があります。
概要
- 参考リンク
- エラーになる場所
- ナビゲーションクリエイターで挟む
- 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テストで実装するのもおすすめです。 準備などは必要ですが、こちらも便利なので機会があれば設定して置けるとテストがもっと便利になります。