Skip to content

Commit 20ff1fb

Browse files
committed
add missing sections
1 parent 11192c4 commit 20ff1fb

File tree

1 file changed

+128
-27
lines changed

1 file changed

+128
-27
lines changed

versioned_docs/version-7.x/testing.md

Lines changed: 128 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,12 @@ If you're using `@react-navigation/stack`, you will only need to mock:
2525
To add the mocks, create a file `jest/setup.js` (or any other file name of your choice) and paste the following code in it:
2626

2727
```js
28-
// include this line for mocking react-native-gesture-handler
28+
// Include this line for mocking react-native-gesture-handler
2929
import 'react-native-gesture-handler/jestSetup';
3030

31-
// include this section and the NativeAnimatedHelper section for mocking react-native-reanimated
31+
// Include this section for mocking react-native-reanimated
3232
jest.mock('react-native-reanimated', () => {
33-
const Reanimated = require('react-native-reanimated/mock');
34-
35-
// The mock for `call` immediately calls the callback which is incorrect
36-
// So we override it with a no-op
37-
Reanimated.default.call = () => {};
38-
39-
return Reanimated;
33+
require('react-native-reanimated/mock');
4034
});
4135

4236
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
@@ -54,53 +48,160 @@ Then we need to use this setup file in our jest config. You can add it under `se
5448

5549
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.
5650

51+
If your configuration works correctly, you can skip this section, but in some unusual cases you will need to mock `react-native-screen` as well. To do so add the following code in `jest/setup.js` file:
52+
53+
```js
54+
// Include this section form mocking react-native-screens
55+
jest.mock('react-native-screens', () => {
56+
// Require actual module instead of a mock
57+
let screens = jest.requireActual('react-native-screens');
58+
59+
// All exports in react-native-screens are getters
60+
// We cannot use spread for cloning as it will call the getters
61+
// So we need to clone it with Object.create
62+
screens = Object.create(
63+
Object.getPrototypeOf(screens),
64+
Object.getOwnPropertyDescriptors(screens)
65+
);
66+
67+
return screens;
68+
});
69+
```
70+
5771
If you're not using Jest, then you'll need to mock these modules according to the test framework you are using.
5872

5973
## Writing tests
6074

6175
We recommend using [React Native Testing Library](https://callstack.github.io/react-native-testing-library/) along with [`jest-native`](https://github.com/testing-library/jest-native) to write your tests.
6276

63-
Example:
77+
We are going to write example tests for Root Navigator defined below:
6478

65-
<Tabs groupId="config" queryString="config">
79+
<Tabs groupId="example" queryString="example">
6680
<TabItem value="static" label="Static" default>
6781

68-
```js name='Testing with jest'
69-
import * as React from 'react';
70-
import { screen, render, fireEvent } from '@testing-library/react-native';
71-
import { createStaticNavigation } from '@react-navigation/native';
72-
import { RootNavigator } from './RootNavigator';
82+
```js
83+
84+
```
85+
86+
</TabItem>
87+
<TabItem value="dynamic" label="Dynamic">
88+
89+
```js
90+
import { Button, Text, View } from 'react-native';
91+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
92+
93+
const Profile = ({ navigation }) => {
94+
return (
95+
<View>
96+
<Text>Profile</Text>
97+
<Button
98+
onPress={() => navigation.navigate('Settings')}
99+
title="Navigate to Settings"
100+
/>
101+
<Button
102+
onPress={() => setTimeout(() => navigation.navigate('Settings'), 10000)}
103+
title="Navigate to Settings with 10000 ms delay"
104+
/>
105+
</View>
106+
);
107+
};
108+
109+
const Settings = () => {
110+
return (
111+
<View>
112+
<Text>Settings</Text>
113+
</View>
114+
);
115+
};
116+
117+
export const RootNavigator = () => {
118+
const Stack = createNativeStackNavigator();
119+
return (
120+
<Stack.Navigator>
121+
<Stack.Screen name="Profile" component={Profile} />
122+
<Stack.Screen name="Settings" component={Settings} />
123+
</Stack.Navigator>
124+
);
125+
};
126+
```
127+
128+
</TabItem>
129+
</Tabs>
130+
131+
Test Example:
132+
133+
<Tabs groupId="example" queryString="example">
134+
<TabItem value="static" label="Static" default>
73135

74-
const Navigation = createStaticNavigation(RootNavigator);
136+
```js
137+
138+
```
75139

76-
test('shows profile screen when View Profile is pressed', () => {
77-
render(<Navigation />);
140+
</TabItem>
141+
<TabItem value="dynamic" label="Dynamic">
78142

79-
fireEvent.press(screen.getByText('View Profile'));
143+
```js
144+
import { expect, test } from '@jest/globals';
145+
import { fireEvent, render, screen } from '@testing-library/react-native';
146+
import { NavigationContainer } from '@react-navigation/native';
147+
import { RootNavigator } from './RootNavigator';
80148

81-
expect(screen.getByText('My Profile')).toBeOnTheScreen();
149+
test('shows settings screen when Navigate to Settings is pressed', () => {
150+
render(
151+
<NavigationContainer>
152+
<RootNavigator />
153+
</NavigationContainer>
154+
);
155+
156+
fireEvent.press(screen.getByText('Navigate to Settings'));
157+
expect(screen.getByText('Settings')).toBeOnTheScreen();
82158
});
83159
```
84160

161+
</TabItem>
162+
</Tabs>
163+
164+
For writing tests that include times functions you will need to use [Fake Timers](https://jestjs.io/docs/timer-mocks). They will replace times function implementation to use time from the fake clock.
165+
166+
Test Example:
167+
168+
<Tabs groupId="example" queryString="example">
169+
<TabItem value="static" label="Static" default>
170+
171+
```js
172+
173+
```
174+
85175
</TabItem>
86176
<TabItem value="dynamic" label="Dynamic">
87177

88-
```js name='Testing with jest'
89-
import * as React from 'react';
90-
import { screen, render, fireEvent } from '@testing-library/react-native';
178+
```js
179+
import { expect, jest, test } from '@jest/globals';
180+
import { act, fireEvent, render, screen } from '@testing-library/react-native';
91181
import { NavigationContainer } from '@react-navigation/native';
92182
import { RootNavigator } from './RootNavigator';
93183

94-
test('shows profile screen when View Profile is pressed', () => {
184+
test('navigates to settings screen after 10000 ms delay', async () => {
185+
// Enable fake timers
186+
jest.useFakeTimers();
187+
95188
render(
96189
<NavigationContainer>
97190
<RootNavigator />
98191
</NavigationContainer>
99192
);
100193

101-
fireEvent.press(screen.getByText('View Profile'));
194+
fireEvent.press(screen.getByText('Navigate to Settings with 10000 ms delay'));
195+
196+
expect(screen.queryByText('Profile')).toBeOnTheScreen();
197+
expect(screen.queryByText('Settings')).not.toBeOnTheScreen();
198+
199+
// jest.runAllTimers causes React state updates
200+
// So it should be wrapped into act
201+
act(() => jest.advanceTimersByTime(10000));
102202

103-
expect(screen.getByText('My Profile')).toBeOnTheScreen();
203+
expect(screen.queryByText('Profile')).not.toBeOnTheScreen();
204+
expect(screen.queryByText('Settings')).toBeOnTheScreen();
104205
});
105206
```
106207

0 commit comments

Comments
 (0)