Skip to content

Commit 199de62

Browse files
authored
Adding tests for React Navigation Drawer Navigator (#624)
* test - React Navigation Drawer * docs - updated documentation for the website * docs - added Drawer Navigator test to the website * actioning PR suggestions * docs - simple doc cleanup;
1 parent a1afddb commit 199de62

File tree

10 files changed

+257
-8
lines changed

10 files changed

+257
-8
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'react-native-gesture-handler/jestSetup';
2+
3+
jest.mock('react-native-reanimated', () => {
4+
const Reanimated = require('react-native-reanimated/mock');
5+
6+
// The mock for `call` immediately calls the callback which is incorrect
7+
// So we override it with a no-op
8+
Reanimated.default.call = () => {};
9+
10+
return Reanimated;
11+
});
12+
13+
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
14+
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');

examples/reactnavigation/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
preset: 'react-native',
3-
setupFiles: ['./node_modules/react-native-gesture-handler/jestSetup.js'],
3+
setupFiles: ['./jest-setup.js'],
44
transformIgnorePatterns: [
55
'node_modules/(?!(jest-)?react-native|@react-native-community|@react-navigation)',
66
],

examples/reactnavigation/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
},
99
"dependencies": {
1010
"@react-native-community/masked-view": "^0.1.9",
11+
"@react-navigation/drawer": "^5.11.4",
1112
"@react-navigation/native": "^5.1.6",
1213
"@react-navigation/stack": "^5.2.13",
1314
"prop-types": "^15.7.2",

examples/reactnavigation/src/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'react-native-gesture-handler';
12
import React from 'react';
23
import { StatusBar, StyleSheet, View } from 'react-native';
34
import { NavigationContainer } from '@react-navigation/native';
@@ -9,7 +10,6 @@ export default function App() {
910
<NavigationContainer>
1011
<View style={styles.container}>
1112
<StatusBar barStyle="dark-content" />
12-
1313
<AppNavigator />
1414
</View>
1515
</NavigationContainer>

examples/reactnavigation/src/AppNavigator.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'react-native-gesture-handler';
21
import * as React from 'react';
32
import { createStackNavigator } from '@react-navigation/stack';
43

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'react-native-gesture-handler';
2+
import React from 'react';
3+
import { NavigationContainer } from '@react-navigation/native';
4+
5+
import DrawerAppNavigator from './DrawerAppNavigator';
6+
7+
export default function DrawerApp() {
8+
return (
9+
<NavigationContainer>
10+
<DrawerAppNavigator />
11+
</NavigationContainer>
12+
);
13+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react';
2+
import {createDrawerNavigator} from '@react-navigation/drawer';
3+
import {View, Button, Text} from 'react-native';
4+
5+
const { Screen, Navigator } = createDrawerNavigator();
6+
7+
function HomeScreen({ navigation }) {
8+
return (
9+
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
10+
<Text>Welcome!</Text>
11+
<Button
12+
onPress={() => navigation.navigate('Notifications')}
13+
title="Go to notifications"
14+
/>
15+
</View>
16+
);
17+
}
18+
19+
function NotificationsScreen({ navigation }) {
20+
return (
21+
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
22+
<Text>This is the notifications screen</Text>
23+
<Button onPress={() => navigation.goBack()} title="Go back home" />
24+
</View>
25+
);
26+
}
27+
28+
export default function Navigation() {
29+
return (
30+
<Navigator>
31+
<Screen name="Home" component={HomeScreen} />
32+
<Screen name="Notifications" component={NotificationsScreen} />
33+
</Navigator>
34+
);
35+
}

examples/reactnavigation/src/__tests__/AppNavigator.test.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ import { render, fireEvent } from '@testing-library/react-native';
44

55
import AppNavigator from '../AppNavigator';
66

7-
// Silence the warning https://github.com/facebook/react-native/issues/11094#issuecomment-263240420
8-
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
9-
107
describe('Testing react navigation', () => {
118
test('page contains the header and 10 items', async () => {
129
const component = (
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import { NavigationContainer } from '@react-navigation/native';
3+
import { render, fireEvent } from '@testing-library/react-native';
4+
5+
import DrawerAppNavigator from '../DrawerAppNavigator';
6+
7+
describe('Testing react navigation', () => {
8+
test('screen contains a button linking to the notifications page', async () => {
9+
const component = (
10+
<NavigationContainer>
11+
<DrawerAppNavigator />
12+
</NavigationContainer>
13+
);
14+
15+
const { findByText, findAllByText } = render(component);
16+
const button = await findByText('Go to notifications');
17+
18+
expect(button).toBeTruthy();
19+
});
20+
21+
test('clicking on the button takes you to the notifications screen', async () => {
22+
const component = (
23+
<NavigationContainer>
24+
<DrawerAppNavigator />
25+
</NavigationContainer>
26+
);
27+
28+
const { queryByText, findByText } = render(component);
29+
const oldScreen = queryByText('Welcome!');
30+
const button = await findByText('Go to notifications');
31+
32+
expect(oldScreen).toBeTruthy();
33+
34+
fireEvent(button, 'press');
35+
const newScreen = await findByText('This is the notifications screen');
36+
37+
expect(newScreen).toBeTruthy();
38+
});
39+
});

website/docs/ReactNavigation.md

Lines changed: 153 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ title: React Navigation
55

66
This section deals with integrating `@testing-library/react-native` with `react-navigation`, using Jest.
77

8-
## Setting up
8+
## Stack Navigator
9+
10+
### Setting up
911

1012
Install the packages required for React Navigation. For this example, we will use a [stack navigator](https://reactnavigation.org/docs/stack-navigator/) to transition to the second page when any of the items are clicked on.
1113

@@ -122,7 +124,7 @@ const styles = StyleSheet.create({
122124
});
123125
```
124126

125-
## Setting up the test environment
127+
### Setting up the test environment
126128

127129
Install required dev dependencies:
128130

@@ -147,6 +149,8 @@ Notice the 2 entries that don't come with the default React Native project:
147149
- `setupFiles` – an array of files that Jest is going to execute before running your tests. In this case, we run `react-native-gesture-handler/jestSetup.js` which sets up necessary mocks for `react-native-gesture-handler` native module
148150
- `transformIgnorePatterns` – an array of paths that Jest ignores when transforming code. In this case, the negative lookahead regular expression is used, to tell Jest to transform (with Babel) every package inside `node_modules/` that starts with `react-native`, `@react-native-community` or `@react-navigation` (added by us, the rest is in `react-native` preset by default, so you don't have to worry about it).
149151

152+
### Example tests
153+
150154
For this example, we are going to test out two things. The first thing is that the page is laid out as expected. The second, and most important, is that the page will transition to the detail screen when any item is tapped on.
151155

152156
Let's add a [`AppNavigator.test.js`](https://github.com/callstack/react-native-testing-library/blob/master/examples/reactnavigation/src/__tests__/AppNavigator.js) file in `src/__tests__` directory:
@@ -198,6 +202,153 @@ describe('Testing react navigation', () => {
198202
});
199203
```
200204

205+
## Drawer Navigator
206+
207+
Testing the Drawer Navigation requires an additional setup step for mocking the Reanimated library.
208+
209+
### Setting up
210+
211+
Install the packages required for React Navigation. For this example, we will use a [drawer navigator](https://reactnavigation.org/docs/drawer-navigator/) to transition between a home screen and an additional screen.
212+
213+
```
214+
$ yarn add @react-native-community/masked-view @react-navigation/native @react-navigation/drawer react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens
215+
```
216+
217+
Create a [`./DrawerAppNavigator.js`](https://github.com/callstack/react-native-testing-library/blob/master/examples/reactnavigation/src/DrawerAppNavigator.js) component which will list the navigation stack:
218+
219+
```jsx
220+
import 'react-native-gesture-handler';
221+
import React from 'react';
222+
import {createDrawerNavigator} from '@react-navigation/drawer';
223+
224+
const { Screen, Navigator } = createDrawerNavigator();
225+
226+
export default function Navigation() {
227+
return (
228+
<Navigator>
229+
<Screen name="Home" component={HomeScreen} />
230+
<Screen name="Notifications" component={NotificationsScreen} />
231+
</Navigator>
232+
);
233+
}
234+
```
235+
236+
Create your two screens which we will transition to and from:
237+
238+
```jsx
239+
function HomeScreen({ navigation }) {
240+
return (
241+
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
242+
<Text>Welcome!</Text>
243+
<Button
244+
onPress={() => navigation.navigate('Notifications')}
245+
title="Go to notifications"
246+
/>
247+
</View>
248+
);
249+
}
250+
251+
function NotificationsScreen({ navigation }) {
252+
return (
253+
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
254+
<Text>This is the notifications screen</Text>
255+
<Button onPress={() => navigation.goBack()} title="Go back home" />
256+
</View>
257+
);
258+
}
259+
```
260+
261+
### Setting up the test environment
262+
263+
Install required dev dependencies:
264+
265+
```
266+
$ yarn add -D jest @testing-library/react-native
267+
```
268+
269+
Create a [`mock file`](https://github.com/callstack/react-native-testing-library/blob/master/examples/reactnavigation/jest-mocks.js) necessary for your tests:
270+
271+
```jsx
272+
import 'react-native-gesture-handler/jestSetup';
273+
274+
jest.mock('react-native-reanimated', () => {
275+
const Reanimated = require('react-native-reanimated/mock');
276+
277+
// The mock for `call` immediately calls the callback which is incorrect
278+
// So we override it with a no-op
279+
Reanimated.default.call = () => {};
280+
281+
return Reanimated;
282+
});
283+
284+
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
285+
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
286+
```
287+
288+
Create your `jest.config.js` file (or place the following properties in your `package.json` as a "jest" property)
289+
290+
```js
291+
module.exports = {
292+
preset: 'react-native',
293+
setupFiles: ['./jest-mocks.js'],
294+
transformIgnorePatterns: [
295+
'node_modules/(?!(jest-)?react-native|@react-native-community|@react-navigation)',
296+
],
297+
};
298+
```
299+
300+
Make sure that the path to the file in `setupFiles` is correct. Jest will run these files before running your tests, so it's the best place to put your global mocks.
301+
302+
This setup is copied from the [React Navigation documentation](https://reactnavigation.org/docs/testing/).
303+
304+
### Example tests
305+
306+
For this example, we are going to test out two things. The first thing is that the screen is loaded correctly. The second, and most important, is that the page will transition to the notifications screen when the button is tapped on.
307+
308+
Let's add a [`DrawerAppNavigator.test.js`](https://github.com/callstack/react-native-testing-library/blob/master/examples/reactnavigation/src/__tests__/DrawerAppNavigator.js) file in `src/__tests__` directory:
309+
310+
```jsx
311+
import React from 'react';
312+
import { NavigationContainer } from '@react-navigation/native';
313+
import { render, fireEvent } from '@testing-library/react-native';
314+
315+
import DrawerAppNavigator from '../DrawerAppNavigator';
316+
317+
describe('Testing react navigation', () => {
318+
test('screen contains a button linking to the notifications page', async () => {
319+
const component = (
320+
<NavigationContainer>
321+
<DrawerAppNavigator />
322+
</NavigationContainer>
323+
);
324+
325+
const { findByText, findAllByText } = render(component);
326+
const button = await findByText('Go to notifications');
327+
328+
expect(button).toBeTruthy();
329+
});
330+
331+
test('clicking on the button takes you to the notifications screen', async () => {
332+
const component = (
333+
<NavigationContainer>
334+
<DrawerAppNavigator />
335+
</NavigationContainer>
336+
);
337+
338+
const { queryByText, findByText } = render(component);
339+
const oldScreen = queryByText('Welcome!');
340+
const button = await findByText('Go to notifications');
341+
342+
expect(oldScreen).toBeTruthy();
343+
344+
fireEvent(button, 'press');
345+
const newScreen = await findByText('This is the notifications screen');
346+
347+
expect(newScreen).toBeTruthy();
348+
});
349+
});
350+
```
351+
201352
## Running tests
202353

203354
To run the tests, place a test script inside your `package.json`

0 commit comments

Comments
 (0)