Skip to content

Commit 77e557f

Browse files
committed
Change first 2 examples of 'Writing Tests' section
1 parent 116442f commit 77e557f

File tree

1 file changed

+131
-94
lines changed

1 file changed

+131
-94
lines changed

versioned_docs/version-7.x/testing.md

Lines changed: 131 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,19 @@ We will go through some real-world case test code examples. Each code example co
8383

8484
### Example 1
8585

86-
Navigate to settings screen by "Go to Settings" button press.
86+
Navigate to settings screen by tab bar button press.
8787

8888
<Tabs groupId="example" queryString="example">
8989
<TabItem value="static" label="Static" default>
9090

9191
```js
92-
import { useNavigation } from '@react-navigation/native';
93-
import { createStackNavigator } from '@react-navigation/stack';
94-
import { Button, Text, View } from 'react-native';
92+
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
93+
import { Text, View } from 'react-native';
9594

9695
const HomeScreen = () => {
97-
const navigation = useNavigation();
98-
9996
return (
10097
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
10198
<Text>Home screen</Text>
102-
<Button
103-
onPress={() => navigation.navigate('Settings')}
104-
title="Go to Settings"
105-
/>
10699
</View>
107100
);
108101
};
@@ -115,10 +108,23 @@ const SettingsScreen = () => {
115108
);
116109
};
117110

118-
export const StackNavigator = createStackNavigator({
111+
export const TabNavigator = createBottomTabNavigator({
119112
screens: {
120-
Home: HomeScreen,
121-
Settings: SettingsScreen,
113+
Home: {
114+
screen: HomeScreen,
115+
options: {
116+
tabBarButtonTestID: 'homeTabBarButton',
117+
},
118+
},
119+
Settings: {
120+
screen: SettingsScreen,
121+
options: {
122+
tabBarButtonTestID: 'settingsTabBarButton',
123+
},
124+
},
125+
},
126+
screenOptions: {
127+
headerShown: false,
122128
},
123129
});
124130
```
@@ -127,17 +133,13 @@ export const StackNavigator = createStackNavigator({
127133
<TabItem value="dynamic" label="Dynamic">
128134

129135
```js
130-
import { createStackNavigator } from '@react-navigation/stack';
131-
import { Button, Text, View } from 'react-native';
136+
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
137+
import { Text, View } from 'react-native';
132138

133-
const HomeScreen = ({ navigation }) => {
139+
const HomeScreen = () => {
134140
return (
135141
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
136142
<Text>Home screen</Text>
137-
<Button
138-
onPress={() => navigation.navigate('Settings')}
139-
title="Go to Settings"
140-
/>
141143
</View>
142144
);
143145
};
@@ -150,13 +152,26 @@ const SettingsScreen = () => {
150152
);
151153
};
152154

153-
export const StackNavigator = () => {
154-
const Stack = createStackNavigator();
155+
const Tab = createBottomTabNavigator();
156+
157+
export const TabNavigator = () => {
155158
return (
156-
<Stack.Navigator>
157-
<Stack.Screen name="Home" component={HomeScreen} />
158-
<Stack.Screen name="Settings" component={SettingsScreen} />
159-
</Stack.Navigator>
159+
<Tab.Navigator screenOptions={{ headerShown: false }}>
160+
<Tab.Screen
161+
name="Home"
162+
component={HomeScreen}
163+
options={{
164+
tabBarButtonTestID: 'homeTabBarButton',
165+
}}
166+
/>
167+
<Tab.Screen
168+
name="Settings"
169+
component={SettingsScreen}
170+
options={{
171+
tabBarButtonTestID: 'settingsTabBarButton',
172+
}}
173+
/>
174+
</Tab.Navigator>
160175
);
161176
};
162177
```
@@ -172,14 +187,18 @@ import { expect, test } from '@jest/globals';
172187
import { createStaticNavigation } from '@react-navigation/native';
173188
import { fireEvent, render, screen } from '@testing-library/react-native';
174189

175-
import { StackNavigator } from './StackNavigator';
190+
import { TabNavigator } from './TabNavigator';
176191

177-
test('navigates to settings by "Go to Settings" button press', () => {
178-
const StackNavigation = createStaticNavigation(StackNavigator);
179-
render(<StackNavigation />);
192+
test('navigates to settings by tab bar button press', () => {
193+
const TabNavigation = createStaticNavigation(TabNavigator);
194+
render(<TabNavigation />);
180195

181-
fireEvent.press(screen.queryByText('Go to Settings'));
182-
expect(screen.queryByText('Settings screen')).toBeOnTheScreen();
196+
const button = screen.getByTestId('settingsTabBarButton');
197+
198+
const event = {};
199+
fireEvent.press(button, event);
200+
201+
expect(screen.getByText('Settings screen')).toBeOnTheScreen();
183202
});
184203
```
185204

@@ -191,59 +210,84 @@ import { expect, test } from '@jest/globals';
191210
import { NavigationContainer } from '@react-navigation/native';
192211
import { fireEvent, render, screen } from '@testing-library/react-native';
193212

194-
import { StackNavigator } from './StackNavigator';
213+
import { TabNavigator } from './TabNavigator';
195214

196-
test('navigates to settings by "Go to Settings" button press', () => {
215+
test('navigates to settings by tab bar button press', () => {
197216
render(
198217
<NavigationContainer>
199-
<StackNavigator />
218+
<TabNavigator />
200219
</NavigationContainer>
201220
);
202221

203-
fireEvent.press(screen.queryByText('Go to Settings'));
204-
expect(screen.queryByText('Settings screen')).toBeOnTheScreen();
222+
const button = screen.getByTestId('settingsTabBarButton');
223+
224+
const event = {};
225+
fireEvent.press(button, event);
226+
227+
expect(screen.getByText('Settings screen')).toBeOnTheScreen();
205228
});
206229
```
207230

208231
</TabItem>
209232
</Tabs>
210233

211-
We use `FireEvent` to press button and `expect` to check if rendered screen's content matches settings screen.
234+
We get the settings tab bar button using a `testID` assigned to it, press it using `fireEvent` and check if rendered content is correct.
235+
236+
Tab bar buttons `handlePress` function expects to receive `GestureResponderEvent`. To avoid error you should pass `event` object as the second argument of `fireEvent`.
237+
238+
```js
239+
// Pass event object to avoid error
240+
const event = {};
241+
fireEvent.press(button, event);
242+
```
212243

213244
### Example 2
214245

215-
Navigate to settings screen by tab bar button press.
246+
Show text on another screen after transition to it ends.
216247

217248
<Tabs groupId="example" queryString="example">
218249
<TabItem value="static" label="Static" default>
219250

220251
```js
221-
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
222-
import { Text, View } from 'react-native';
252+
import { useNavigation } from '@react-navigation/native';
253+
import { createStackNavigator } from '@react-navigation/stack';
254+
import { Button, Text, View } from 'react-native';
255+
import { useEffect, useState } from 'react';
223256

224257
const HomeScreen = () => {
258+
const navigation = useNavigation();
259+
225260
return (
226261
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
227262
<Text>Home screen</Text>
263+
<Button
264+
onPress={() => navigation.navigate('Surprise')}
265+
title="Click here!"
266+
/>
228267
</View>
229268
);
230269
};
231270

232-
const SettingsScreen = () => {
271+
const SurpriseScreen = () => {
272+
const navigation = useNavigation();
273+
274+
const [textVisible, setTextVisible] = useState(false);
275+
276+
useEffect(() => {
277+
navigation.addListener('transitionEnd', () => setTextVisible(true));
278+
}, [navigation]);
279+
233280
return (
234281
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
235-
<Text>Settings screen</Text>
282+
{textVisible ? <Text>Surprise!</Text> : ''}
236283
</View>
237284
);
238285
};
239286

240-
export const TabNavigator = createBottomTabNavigator({
287+
export const StackNavigator = createStackNavigator({
241288
screens: {
242289
Home: HomeScreen,
243-
Settings: SettingsScreen,
244-
},
245-
screenOptions: {
246-
headerShown: false,
290+
Surprise: SurpriseScreen,
247291
},
248292
});
249293
```
@@ -252,33 +296,43 @@ export const TabNavigator = createBottomTabNavigator({
252296
<TabItem value="dynamic" label="Dynamic">
253297

254298
```js
255-
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
256-
import { Text, View } from 'react-native';
299+
import { createStackNavigator } from '@react-navigation/stack';
300+
import { useEffect, useState } from 'react';
301+
import { Button, Text, View } from 'react-native';
257302

258-
const HomeScreen = () => {
303+
const HomeScreen = ({ navigation }) => {
259304
return (
260305
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
261306
<Text>Home screen</Text>
307+
<Button
308+
onPress={() => navigation.navigate('Surprise')}
309+
title="Click here!"
310+
/>
262311
</View>
263312
);
264313
};
265314

266-
const SettingsScreen = () => {
315+
const SurpriseScreen = ({ navigation }) => {
316+
const [textVisible, setTextVisible] = useState(false);
317+
318+
useEffect(() => {
319+
navigation.addListener('transitionEnd', () => setTextVisible(true));
320+
}, [navigation]);
321+
267322
return (
268323
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
269-
<Text>Settings screen</Text>
324+
{textVisible ? <Text>Surprise!</Text> : ''}
270325
</View>
271326
);
272327
};
273328

274-
const Tab = createBottomTabNavigator();
275-
276-
export const TabNavigator = () => {
329+
export const StackNavigator = () => {
330+
const Stack = createStackNavigator();
277331
return (
278-
<Tab.Navigator screenOptions={{ headerShown: false }}>
279-
<Tab.Screen name="Home" component={HomeScreen} />
280-
<Tab.Screen name="Settings" component={SettingsScreen} />
281-
</Tab.Navigator>
332+
<Stack.Navigator>
333+
<Stack.Screen name="Home" component={HomeScreen} />
334+
<Stack.Screen name="Surprise" component={SurpriseScreen} />
335+
</Stack.Navigator>
282336
);
283337
};
284338
```
@@ -294,21 +348,19 @@ import { expect, jest, test } from '@jest/globals';
294348
import { createStaticNavigation } from '@react-navigation/native';
295349
import { act, fireEvent, render, screen } from '@testing-library/react-native';
296350

297-
import { TabNavigator } from './TabNavigator';
351+
import { StackNavigator } from './StackNavigator';
298352

299-
test('navigates to settings by tab bar button press', () => {
353+
test('surprise text appears after transition to surprise screen is complete', () => {
300354
jest.useFakeTimers();
301355

302-
const TabNavigation = createStaticNavigation(TabNavigator);
303-
render(<TabNavigation />);
356+
const StackNavigation = createStaticNavigation(StackNavigator);
357+
render(<StackNavigation />);
304358

305-
const button = screen.getByRole('button', { name: 'Settings, tab, 2 of 2' });
359+
fireEvent.press(screen.queryByText('Click here!'));
306360

307-
const event = {};
308-
fireEvent.press(button, event);
361+
expect(screen.queryByText('Surprise!')).not.toBeOnTheScreen();
309362
act(() => jest.runAllTimers());
310-
311-
expect(screen.queryByText('Settings screen')).toBeOnTheScreen();
363+
expect(screen.getByText('Surprise!')).toBeOnTheScreen();
312364
});
313365
```
314366

@@ -320,48 +372,31 @@ import { expect, jest, test } from '@jest/globals';
320372
import { NavigationContainer } from '@react-navigation/native';
321373
import { act, fireEvent, render, screen } from '@testing-library/react-native';
322374

323-
import { TabNavigator } from './TabNavigator';
375+
import { StackNavigator } from './StackNavigator';
324376

325-
test('navigates to settings by tab bar button press', () => {
377+
test('surprise text appears after transition to surprise screen is complete', () => {
326378
jest.useFakeTimers();
327379

328380
render(
329381
<NavigationContainer>
330-
<TabNavigator />
382+
<StackNavigator />
331383
</NavigationContainer>
332384
);
333385

334-
const button = screen.getByRole('button', { name: 'Settings, tab, 2 of 2' });
386+
fireEvent.press(screen.queryByText('Click here!'));
335387

336-
const event = {};
337-
fireEvent.press(button, event);
388+
expect(screen.queryByText('Surprise!')).not.toBeOnTheScreen();
338389
act(() => jest.runAllTimers());
339-
340-
expect(screen.queryByText('Settings screen')).toBeOnTheScreen();
390+
expect(screen.getByText('Surprise!')).toBeOnTheScreen();
341391
});
342392
```
343393

344394
</TabItem>
345395
</Tabs>
346396

347-
We get settings tab bar button, press it and check if rendered content is correct.
348-
349-
To find settings tab bar button you cannot use `queryByText`, because there is no text that can be queried. You can use `getByRole` instead and pass object with `name` as the second argument.
350-
351-
```js
352-
// Pass object with settings tab name
353-
const button = screen.getByRole('button', { name: 'Settings, tab, 2 of 2' });
354-
```
355-
356-
Tab bar buttons `handlePress` function expects to receive `GestureResponderEvent`. To avoid error you should pass `event` object as the second argument of `fireEvent`.
397+
We press the "Click here!" button using `fireEvent` and check that the text does not appear right away but only after the transition between screens ends.
357398

358-
```js
359-
// Pass event object to avoid error
360-
const event = {};
361-
fireEvent.press(button, event);
362-
```
363-
364-
While writing tests containing navigation with animations you need to wait until animations finish before querying components. To do so, you have to use `fake timers`. [`Fake Timers`](https://jestjs.io/docs/timer-mocks) replace real implementation of times function to use fake clock. They allow you to instantly skip animation time. To avoid getting state change error, wrap `runAllTimers` in `act`.
399+
While writing tests containing navigation with animations (in this example we have a `StackNavigator`, which uses an animation for the transition based on the platform and OS version) you need to wait until animations finish before proceeding further. To do so, you have to use `fake timers`. [`Fake Timers`](https://jestjs.io/docs/timer-mocks) replace real implementation of times function to use fake clock. They allow you to instantly skip animation time. To avoid getting state change error, wrap `runAllTimers` in `act`.
365400

366401
```js
367402
// Enable fake timers
@@ -374,6 +409,8 @@ jest.useFakeTimers();
374409
act(() => jest.runAllTimers());
375410
```
376411

412+
If we hadn't used fake timers in this example, the test would have failed.
413+
377414
### Example 3
378415

379416
Always displays settings screen after settings tab bar button press.

0 commit comments

Comments
 (0)