Skip to content

Commit a218bbc

Browse files
docs: refactor react-navigation example with React Nav team feedback (#1253)
1 parent 6fba252 commit a218bbc

File tree

4 files changed

+26
-47
lines changed

4 files changed

+26
-47
lines changed

examples/react-navigation/README.md

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
# RNTL example app for React Navigation
22

3-
This example shows how to write integration tests using React Navigation without mocking it.
3+
This example shows how to write integration tests using React Navigation without mocking it. Presented approach has been consulted with and influenced by React Navigation team.
44

5-
There are two types of tests:
6-
1. integration tests operating on whole navigators, they should use `renderNavigator` helper to render a navigator component used in the app. It is useful when you want to test a scenario that includes multiple screens.
7-
2. single screen tests where you would pass mock `navigation` prop, built using `buildNavigationMock()` helper, and `route` prop to the screen component using regular `render` function.
5+
## Recommended tests
6+
7+
There are two types of recommeded tests:
8+
1. Tests operating on navigator level - these use `renderNavigator` helper to render a navigator component used in the app. It is useful when you want to test a scenario that includes multiple screens.
9+
2. Tests operating on single screen level - these use regular `render` helper but require refactoring screen components into `Screen` and `ScreenContent` components. Where `Screen` receives React Navigation props and/or uses hooks like `useNavigation` while `ScreenContent` does not have a direct relation to React Navigation API but gets props from `Screen` and calls relevant callbacks to trigger navigation.
810

911
> Note that this example applies `includeHiddenElements: false` by default, so all queries will ignore elements on the hidden screens, e.g. inactive tabs or screens present in stack navigators. This option is enabled in `jest-setup.js` file, using `defaultIncludeHiddenElements: false` option to `configure` function.
12+
13+
## Non-recommended tests
14+
15+
There also exists another popular type of screen level tests, where users mock React Navigation objects like `navigation`, `route` and/or hooks like `useNavigation`, etc. We don't recommend this way of testing. **Mocking internal parts of the libraries is effectively testing implementation details, which goes against the Testing Library's [Guiding Principles](https://testing-library.com/docs/guiding-principles/)**.
16+

examples/react-navigation/src/screens/DetailsScreen.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import * as React from 'react';
22
import { StyleSheet, View, Text, Pressable } from 'react-native';
3-
import { useNavigation } from '@react-navigation/native';
43

5-
export default function DetailsScreen({ route }) {
4+
export default function DetailsScreen({ navigation, route }) {
65
const item = route.params;
6+
return (
7+
<DetailsScreenContent item={item} onGoBack={() => navigation.goBack()} />
8+
);
9+
}
710

11+
export function DetailsScreenContent({ item, onGoBack }) {
812
return (
913
<View>
1014
<Text accessibilityRole="header" style={styles.header}>
@@ -14,16 +18,14 @@ export default function DetailsScreen({ route }) {
1418
The number you have chosen is {item.value}.
1519
</Text>
1620

17-
<BackButton />
21+
<BackButton onPress={onGoBack} />
1822
</View>
1923
);
2024
}
2125

22-
function BackButton() {
23-
const navigation = useNavigation();
24-
26+
function BackButton({ onPress }) {
2527
return (
26-
<Pressable accessibilityRole="button" onPress={() => navigation.goBack()}>
28+
<Pressable accessibilityRole="button" onPress={onPress}>
2729
<Text>Go Back</Text>
2830
</Pressable>
2931
);
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,18 @@
11
import * as React from 'react';
22
import { render, screen, fireEvent } from '@testing-library/react-native';
3-
import { useNavigation } from '@react-navigation/native';
4-
import { buildNavigationMock } from '../test-utils';
5-
import DetailsScreen from './DetailsScreen';
6-
7-
jest.mock('@react-navigation/native', () => {
8-
const originalModule = jest.requireActual('@react-navigation/native');
9-
10-
return {
11-
...originalModule,
12-
useNavigation: jest.fn(),
13-
};
14-
});
15-
16-
let navigation;
17-
18-
// Reset navigation before each test
19-
beforeEach(() => {
20-
navigation = buildNavigationMock();
21-
useNavigation.mockImplementation(() => navigation);
22-
});
3+
import { DetailsScreenContent } from './DetailsScreen';
234

245
test('Details screen contains the header and content', () => {
25-
const params = {
6+
const item = {
267
id: 100,
278
title: 'Item 100',
289
value: 100,
2910
};
3011

12+
const onGoBack = jest.fn();
13+
3114
// Passing both navigation and route to the screen as props
32-
render(<DetailsScreen navigation={navigation} route={{ params }} />);
15+
render(<DetailsScreenContent item={item} onGoBack={onGoBack} />);
3316

3417
expect(
3518
screen.getByRole('header', { name: 'Details for Item 100' })
@@ -38,5 +21,5 @@ test('Details screen contains the header and content', () => {
3821

3922
// Note: Go Back button get navigation from `useNavigation` hook
4023
fireEvent.press(screen.getByRole('button', { name: 'Go Back' }));
41-
expect(navigation.goBack).toHaveBeenCalledTimes(1);
24+
expect(onGoBack).toHaveBeenCalledTimes(1);
4225
});

examples/react-navigation/src/test-utils.js

-13
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,3 @@ import { render } from '@testing-library/react-native';
1010
export function renderNavigator(ui) {
1111
return render(<NavigationContainer>{ui}</NavigationContainer>);
1212
}
13-
14-
export function buildNavigationMock() {
15-
return {
16-
navigate: jest.fn(),
17-
reset: jest.fn(),
18-
goBack: jest.fn(),
19-
dispatch: jest.fn(),
20-
isFocused: jest.fn(() => true),
21-
setParams: jest.fn(),
22-
setOptions: jest.fn(),
23-
addListener: jest.fn(),
24-
};
25-
}

0 commit comments

Comments
 (0)