Skip to content
This repository was archived by the owner on Aug 1, 2020. It is now read-only.

Files

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Latest commit

author
Steve Galili
Jun 18, 2020
b2b3c85 · Jun 18, 2020

History

History
190 lines (162 loc) · 5.54 KB

example-navigation.md

File metadata and controls

190 lines (162 loc) · 5.54 KB
id title sidebar_label
example-navigation
Navigation
Navigation

react-navigation v5

// jest.config.js 

// react-native-gesture-handler use native modules, we mock it by using it's build in jestSetup. 
// react-navigations will try to import it's assets, to avoid an error we will mock it by using a custom assets transformer 

module.exports = {
    preset: '@testing-library/react-native',
    setupFiles: ["./node_modules/react-native-gesture-handler/jestSetup.js"],
    moduleNameMapper: {
        "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetsTransformer.js",
        "\\.(css|less)$": "<rootDir>/assetsTransformer.js"
    }
}
// assetsTransformer.js 
// see https://jestjs.io/docs/en/webpack.html#handling-static-assets
const path = require('path')

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';'
  },
}
import React from 'react';
import { Button, Text, View } from 'react-native';
import {NavigationContainer, useNavigationState} from '@react-navigation/native'
import {createStackNavigator} from '@react-navigation/stack'
import {fireEvent, render, wait} from '@testing-library/react-native'

const Home = ({ navigation }) => (
  <View>
    <Text testID="title">Home page</Text>
    <Button title="About page" onPress={() => navigation.navigate('About')} />
  </View>
);
const About = ({ navigation }) => (
  <View>
    <Text testID="title">About page</Text>
    <Button title="About page" onPress={() => navigation.navigate('Home')} />
  </View>
);
const Location = () => (
  <View>
    <Text testID="title">Location page</Text>
    <LocationDisplay />
  </View>
);

const LocationDisplay = (() => {
  const routeName = useNavigationState(state => state.routes[state.index].name);
  return (
    <Text testID="location-display">{routeName}</Text>
  )
});

const Stack = createStackNavigator()

const renderWithNavigation = ({ screens = {}, navigatorConfig = {} } = {})=>
  render(<NavigationContainer>
    <Stack.Navigator {...navigatorConfig}>
      <Stack.Screen name="Home" component={Home} />
      <Stack.Screen name="Location" component={Location} />
      {
        Object.keys(screens).map(name=> <Stack.Screen key={name} name={name} component={screens[name]} />)
      }
    </Stack.Navigator>
  </NavigationContainer>)

test('full app rendering/navigating', () => {
  const { findByText, getByTestId, getByText } = renderWithNavigation({screens: {About}});
  expect(getByTestId('title').props.children).toMatch('Home page');
  fireEvent.press(getByText(/About page/i));
  expect(findByText('About page')).toBeTruthy();
});

test('rendering a component that uses withNavigation', async () => {
  const initialRouteName = 'Location';
  const { getByTestId } = renderWithNavigation({
    navigatorConfig: { initialRouteName },
  });
  await wait(()=> expect(getByTestId('location-display').props.children).toBe(initialRouteName));
});

react-navigation v4

// <project-root-path>/__mocks__/react-native-gesture-handler.js
// react-native-gesture-handler use native modules, we need to mock it. 
import { View } from 'react-native';

export const State = {};
export const PanGestureHandler = View;
export const BaseButton = View;
export const Directions = {};
import React from 'react';
import { Button, Text, View } from 'react-native';
import { createStackNavigator, createAppContainer, withNavigation } from 'react-navigation';

import { render, fireEvent } from '@testing-library/react-native';

// NativeAnimatedHelper is not mocked by default on react native's jest setup file.
jest.mock('NativeAnimatedHelper');

console.warn = arg => {
  const hiddenMessages = [
    'Calling .measureInWindow()',
    'Calling .measureLayout()',
    'Calling .setNativeProps()',
    'Calling .focus()',
    'Calling .blur()',
  ];

  const warningShouldBeHidden = hiddenMessages.some(x => arg.includes(x))

  if (!warningShouldBeHidden) {
    console.warn(arg);
  }
};

const Home = ({ navigation }) => (
  <View>
    <Text testID="title">Home page</Text>
    <Button title="About page" onPress={() => navigation.navigate('About')} />
  </View>
);
const About = ({ navigation }) => (
  <View>
    <Text testID="title">About page</Text>
    <Button title="About page" onPress={() => navigation.navigate('Home')} />
  </View>
);
const Location = () => (
  <View>
    <Text testID="title">Location page</Text>
    <LocationDisplay />
  </View>
);

const LocationDisplay = withNavigation(({ navigation }) => (
  <Text testID="location-display">{navigation.state.routeName}</Text>
));

function renderWithNavigation({ screens = {}, navigatorConfig = {} } = {}) {
  const AppNavigator = createStackNavigator(
    {
      Home,
      About,
      Location,
      ...screens,
    },
    { initialRouteName: 'Home', ...navigatorConfig },
  );

  const App = createAppContainer(AppNavigator);

  return { ...render(<App />), navigationContainer: App };
}

test('full app rendering/navigating', async () => {
  const { findByText, getByTestId, getByText } = renderWithNavigation();
  expect(getByTestId('title').props.children).toMatch('Home page');
  fireEvent.press(getByText(/About page/i));
  await expect(findByText('About page')).toBeTruthy();
});

test('rendering a component that uses withNavigation', () => {
  const initialRouteName = 'Location';
  const { getByTestId } = renderWithNavigation({
    navigatorConfig: { initialRouteName },
  });
  expect(getByTestId('location-display').props.children).toBe(initialRouteName);
});