Skip to content

Commit a8d15a5

Browse files
feature: update react nav example (#1237)
1 parent ad125ea commit a8d15a5

27 files changed

+426
-138
lines changed

.github/workflows/example-apps.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
matrix:
99
node: [14, 16, 18]
10-
example: [basic, redux, reactnavigation]
10+
example: [basic, redux, react-navigation]
1111
name: Test Example
1212
runs-on: ubuntu-latest
1313
timeout-minutes: 10
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# RNTL example app for React Navigation
2+
3+
This example shows how to write integration tests using React Navigation without mocking it.
4+
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.
8+
9+
> 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.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module.exports = {
22
presets: ['module:metro-react-native-babel-preset'],
3+
plugins: ['react-native-reanimated/plugin'],
34
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* eslint-disable import/no-extraneous-dependencies */
2+
import { configure } from '@testing-library/react-native';
3+
4+
// Import Jest Native matchers
5+
import '@testing-library/jest-native/extend-expect';
6+
7+
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
8+
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
9+
10+
// Setup Reanimated mocking for Drawer navigation
11+
global.ReanimatedDataMock = { now: () => Date.now() };
12+
require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests();
13+
14+
// Enable excluding hidden elements from the queries by default
15+
configure({
16+
defaultIncludeHiddenElements: false,
17+
});
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module.exports = {
22
preset: 'react-native',
3-
setupFilesAfterEnv: ['./jest-setup.js'],
3+
setupFilesAfterEnv: [
4+
'./node_modules/react-native-gesture-handler/jestSetup.js',
5+
'./jest-setup.js',
6+
],
47
transformIgnorePatterns: [
58
'node_modules/(?!(jest-)?react-native|@react-native|@react-native-community|@react-navigation)',
69
],
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "react-navigation-example",
3+
"description": "Testing React Navigation with RNTL",
4+
"version": "0.0.1",
5+
"private": true,
6+
"scripts": {
7+
"test": "jest"
8+
},
9+
"dependencies": {
10+
"@react-navigation/bottom-tabs": "^6.4.1",
11+
"@react-navigation/drawer": "^6.5.1",
12+
"@react-navigation/native": "^6.0.14",
13+
"@react-navigation/native-stack": "^6.9.2",
14+
"@react-navigation/stack": "^6.3.5",
15+
"react": "^18.1.0",
16+
"react-native": "^0.70.6",
17+
"react-native-gesture-handler": "^2.8.0",
18+
"react-native-reanimated": "^2.13.0",
19+
"react-native-safe-area-context": "^4.4.1",
20+
"react-native-screens": "^3.18.2"
21+
},
22+
"devDependencies": {
23+
"@babel/core": "^7.20.2",
24+
"@testing-library/jest-native": "^5.3.0",
25+
"@testing-library/react-native": "^11.5.0",
26+
"babel-jest": "^29.3.1",
27+
"jest": "^29.3.0",
28+
"metro-react-native-babel-preset": "^0.72.3",
29+
"react-test-renderer": "^18.1.0"
30+
}
31+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { StatusBar, StyleSheet, View } from 'react-native';
33
import { NavigationContainer } from '@react-navigation/native';
4-
import AppNavigator from './AppNavigator';
4+
import AppNavigator from './NativeStackNavigator';
55

66
export default function App() {
77
return (
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as React from 'react';
2+
import { createDrawerNavigator } from '@react-navigation/drawer';
3+
import DrawerHomeScreen from './screens/DrawerHomeScreen';
4+
import SettingsScreen from './screens/SettingsScreen';
5+
6+
const Drawer = createDrawerNavigator();
7+
8+
export default function Navigation() {
9+
return (
10+
<Drawer.Navigator>
11+
<Drawer.Screen name="Home" component={DrawerHomeScreen} />
12+
<Drawer.Screen name="Settings" component={SettingsScreen} />
13+
</Drawer.Navigator>
14+
);
15+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as React from 'react';
2+
import { screen, fireEvent } from '@testing-library/react-native';
3+
import { renderNavigator } from './test-utils';
4+
import DrawerNavigator from './DrawerNavigator';
5+
6+
test('Changing screens', () => {
7+
renderNavigator(<DrawerNavigator />);
8+
9+
// Assert initial screen
10+
expect(screen.getByRole('header', { name: 'Home screen' })).toBeTruthy();
11+
12+
// Open drawer by pressing button
13+
const toggleButton = screen.getByText('Toggle drawer');
14+
fireEvent.press(toggleButton);
15+
16+
// Assert drawer state
17+
expect(screen.getByRole('button', { name: 'Home' })).toHaveAccessibilityState(
18+
{ selected: true }
19+
);
20+
expect(
21+
screen.getByRole('button', { name: 'Settings' })
22+
).toHaveAccessibilityState({ selected: false });
23+
24+
// Press drawer item
25+
fireEvent.press(screen.getByRole('button', { name: 'Settings' }));
26+
27+
// Assert drawer state after action
28+
expect(screen.getByRole('button', { name: 'Home' })).toHaveAccessibilityState(
29+
{ selected: false }
30+
);
31+
expect(
32+
screen.getByRole('button', { name: 'Settings' })
33+
).toHaveAccessibilityState({ selected: true });
34+
35+
// Assert visible screen
36+
expect(screen.getByRole('header', { name: 'Settings screen' })).toBeTruthy();
37+
expect(screen.queryByRole('header', { name: 'Home screen' })).toBeFalsy();
38+
});
File renamed without changes.

0 commit comments

Comments
 (0)