Skip to content

Commit ad3821a

Browse files
committed
add missing static examples, react-native mock
1 parent f06232c commit ad3821a

File tree

1 file changed

+126
-9
lines changed

1 file changed

+126
-9
lines changed

versioned_docs/version-7.x/testing.md

Lines changed: 126 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Then we need to use this setup file in our jest config. You can add it under `se
4848

4949
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.
5050

51-
If your configuration works correctly, you can skip this section, but in some unusual cases you will need to mock `react-native-screens` as well. To do so add the following code in `jest/setup.js` file:
51+
If your configuration works correctly, you can skip this section, but in some unusual cases you will need to mock `react-native-screens` as well. To add mock of the particular component, e.g. `Screen`, add the following code in `jest/setup.js` file:
5252

5353
```js
5454
// Include this section form mocking react-native-screens
@@ -64,6 +64,11 @@ jest.mock('react-native-screens', () => {
6464
Object.getOwnPropertyDescriptors(screens)
6565
);
6666

67+
// Add mock of the Screen component
68+
Object.defineProperty(screens, 'Screen', {
69+
value: require('react-native').View,
70+
});
71+
6772
return screens;
6873
});
6974
```
@@ -74,13 +79,52 @@ If you're not using Jest, then you'll need to mock these modules according to th
7479

7580
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.
7681

77-
We are going to write example tests illustrating the difference between `navigate` and `push` functions using Root Navigator defined below:
82+
We are going to write example tests illustrating the difference between `navigate` and `push` functions using `RootNavigator` defined below:
7883

7984
<Tabs groupId="example" queryString="example">
8085
<TabItem value="static" label="Static" default>
8186

8287
```js
88+
import { Button, Text, View } from 'react-native';
89+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
90+
import {
91+
createStaticNavigation,
92+
useNavigation,
93+
} from '@react-navigation/native';
8394

95+
const Profile = () => {
96+
const navigation = useNavigation();
97+
return (
98+
<View>
99+
<Text>Profile</Text>
100+
<Button
101+
onPress={() => navigation.navigate('Settings')}
102+
title="Navigate to Settings"
103+
/>
104+
<Button
105+
onPress={() => navigation.push('Settings')}
106+
title="Push Settings"
107+
/>
108+
</View>
109+
);
110+
};
111+
112+
const Settings = () => {
113+
return (
114+
<View>
115+
<Text>Settings</Text>
116+
</View>
117+
);
118+
};
119+
120+
const RootStack = createNativeStackNavigator({
121+
screens: {
122+
Profile,
123+
Settings,
124+
},
125+
});
126+
127+
export const RootNavigator = createStaticNavigation(RootStack);
84128
```
85129

86130
</TabItem>
@@ -102,10 +146,6 @@ const Profile = ({ navigation }) => {
102146
onPress={() => navigation.push('Settings')}
103147
title="Push Settings"
104148
/>
105-
<Button
106-
onPress={() => setTimeout(() => navigation.navigate('Settings'), 10000)}
107-
title="Navigate to Settings with 10000 ms delay"
108-
/>
109149
</View>
110150
);
111151
};
@@ -138,7 +178,25 @@ export const RootNavigator = () => {
138178
<TabItem value="static" label="Static" default>
139179

140180
```js
181+
import { expect, test } from '@jest/globals';
182+
import { fireEvent, render, screen } from '@testing-library/react-native';
183+
import { createNavigationContainerRef } from '@react-navigation/native';
184+
import { RootNavigator } from './RootNavigator';
185+
186+
test('navigates to settings screen twice', () => {
187+
const navigation = createNavigationContainerRef();
188+
render(<RootNavigator ref={navigation} />);
141189

190+
const button = screen.getByText('Navigate to Settings');
191+
fireEvent.press(button);
192+
fireEvent.press(button);
193+
194+
expect(navigation.getState().routes.map((route) => route.name)).toStrictEqual(
195+
['Profile', 'Settings']
196+
);
197+
expect(screen.queryByText('Profile')).not.toBeOnTheScreen();
198+
expect(screen.queryByText('Settings')).toBeOnTheScreen();
199+
});
142200
```
143201

144202
</TabItem>
@@ -182,7 +240,25 @@ test('navigates to settings screen twice', () => {
182240
<TabItem value="static" label="Static" default>
183241

184242
```js
243+
import { expect, test } from '@jest/globals';
244+
import { createNavigationContainerRef } from '@react-navigation/native';
245+
import { fireEvent, render, screen } from '@testing-library/react-native';
246+
import { RootNavigator } from './RootNavigator';
185247

248+
test('pushes settings screen twice', () => {
249+
const navigation = createNavigationContainerRef();
250+
render(<RootNavigator ref={navigation} />);
251+
252+
const button = screen.getByText('Push Settings');
253+
fireEvent.press(button);
254+
fireEvent.press(button);
255+
256+
expect(navigation.getState().routes.map((route) => route.name)).toStrictEqual(
257+
['Profile', 'Settings', 'Settings']
258+
);
259+
expect(screen.queryByText('Profile')).not.toBeOnTheScreen();
260+
expect(screen.queryByText('Settings')).toBeOnTheScreen();
261+
});
186262
```
187263

188264
</TabItem>
@@ -222,13 +298,33 @@ test('pushes settings screen twice', () => {
222298

223299
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.
224300

225-
Let's add another button to the Profile screen which uses `setTimeout`:
301+
Let's add another button to the Profile screen, which uses `setTimeout`:
226302

227303
<Tabs groupId="example" queryString="example">
228304
<TabItem value="static" label="Static" default>
229305

230306
```js
231-
307+
const Profile = () => {
308+
const navigation = useNavigation();
309+
return (
310+
<View>
311+
<Text>Profile</Text>
312+
<Button
313+
onPress={() => navigation.navigate('Settings')}
314+
title="Navigate to Settings"
315+
/>
316+
<Button
317+
onPress={() => navigation.push('Settings')}
318+
title="Push Settings"
319+
/>
320+
{/* Added button */}
321+
<Button
322+
onPress={() => setTimeout(() => navigation.navigate('Settings'), 10000)}
323+
title="Navigate to Settings with 10000 ms delay"
324+
/>
325+
</View>
326+
);
327+
};
232328
```
233329

234330
</TabItem>
@@ -247,7 +343,7 @@ const Profile = ({ navigation }) => {
247343
onPress={() => navigation.push('Settings')}
248344
title="Push Settings"
249345
/>
250-
// Added button
346+
{/* Added button */}
251347
<Button
252348
onPress={() => setTimeout(() => navigation.navigate('Settings'), 10000)}
253349
title="Navigate to Settings with 10000 ms delay"
@@ -266,7 +362,28 @@ Fake timers test example:
266362
<TabItem value="static" label="Static" default>
267363

268364
```js
365+
import { expect, jest, test } from '@jest/globals';
366+
import { act, fireEvent, render, screen } from '@testing-library/react-native';
367+
import { RootNavigator } from './RootNavigator';
368+
369+
test('navigates to settings screen after 10000 ms delay', () => {
370+
// Enable fake timers
371+
jest.useFakeTimers();
269372

373+
render(<RootNavigator />);
374+
375+
fireEvent.press(screen.getByText('Navigate to Settings with 10000 ms delay'));
376+
377+
expect(screen.queryByText('Profile')).toBeOnTheScreen();
378+
expect(screen.queryByText('Settings')).not.toBeOnTheScreen();
379+
380+
// jest.advanceTimersByTime causes React state updates
381+
// So it should be wrapped into act
382+
act(() => jest.advanceTimersByTime(10000));
383+
384+
expect(screen.queryByText('Profile')).not.toBeOnTheScreen();
385+
expect(screen.queryByText('Settings')).toBeOnTheScreen();
386+
});
270387
```
271388

272389
</TabItem>

0 commit comments

Comments
 (0)