How to mock useNavigation hook in react-navigation 5.0 for jest test?
Asked Answered
C

4

24

i want to mock useNavigation hook used inside my functional component. Any workaround how to mock it using jest?

import React from 'react';
import { useNavigation } from '@react-navigation/native';
import { TouchableOpacity } from 'react-native';

const MyComponent = () => {
  const { navigate } = useNavigation();

  const navigateToScreen = () => {
    navigate('myScreen', { param1: 'data1', param2: 'data2' })
  }

  return (<TouchableOpacity onPress={navigateToScreen}>
       Go To Screen
     </TouchableOpacity>)
}

how to test params being passed in navigate function ?

Cephalization answered 13/5, 2020 at 17:41 Comment(2)
Please provide minimal, complete the code under testManthei
@slideshowp2 updated with code and descriptionCephalization
R
57

I know I'm late, but I had the issue where I needed to know know when the navigate function was called.

For it, I mocked the function the following way, so the mockedNavigate would be a jest function that i could use later if i needed to test if the function was actually called:

const mockedNavigate = jest.fn();

jest.mock('@react-navigation/native', () => {
  const actualNav = jest.requireActual('@react-navigation/native');
  return {
    ...actualNav,
    useNavigation: () => ({
      navigate: mockedNavigate,
    }),
  };
});

This allowed me to use this later and I would know if I could navigate properly in my application:

expect(mockedNavigate).toHaveBeenCalledTimes(1);

Hope this helps.

Representative answered 15/6, 2020 at 20:6 Comment(5)
How to mock this navigation V5. with Provider?Pandanus
In order for this to work I had to declare this at the root of the test file (not in a describe or it/test statementNork
It's also possible to put this in your jest setup file and export mockedNavigate. Then in each test file you only have to import that mock function, in my case: import { mockedNavigate } from '../../../../test/setup'.Montana
It's also possible to put this in your jest setup file and export mockedNavigate. Then in each test file you only have to import that mock function, in my case: import { mockedNavigate } from '../../../../test/setup'.Montana
Thanks @Montana for commenting this. I've been thinking how I can access the mocked function, eventually we only need export it for access hahaHygrometry
M
6

Another quite late solution that is a bit cleaner than the previously suggested ones.

const mockedNavigate = jest.fn();

jest.mock('@react-navigation/native', () => (
  { useNavigation: () => ({ navigate: mockedNavigate }) }));

This does not include any other functionality of the navigation object but it will allow you to test in the following way:

expect(mockedNavigate).toHaveBeenCalledTimes(1);

Or with expect.toHaveBeenCalledWith() (here) if more applicable in your specific situation.

Margit answered 9/6, 2021 at 8:54 Comment(0)
I
5
jest.mock("@react-navigation/native", () => {
  const actualNav = jest.requireActual("@react-navigation/native")
  return {
    ...actualNav,
    useFocusEffect: () => jest.fn(),
    useNavigation: () => ({
      navigate: jest.fn(),
    }),
  }
})
Ingunna answered 4/6, 2020 at 21:31 Comment(2)
Can you edit this to include some explanation of what you're doing and why it's a good solution to the problem? That will help the OP and any future readers understand not just what to do, but also why.Deuterogamy
it will also helpful for me if you add some example here.Pandanus
L
0

This might not be a solution for a mock of useNavigation, but I found this helpful to achieve my own intent (spying), and it looks like it would achieve the OP's intent (expecting on calls)

import { CommonActions } from '@react-navigation/routers';
jest.spyOn(CommonActions, 'navigate');

This seems to be where the actions that surface out of the useNavigation hook are defined, too. I was unsuccessful to create a mock on this, but the spy works excellently.

Caveat

I'm using react-navigation 6.

I am calling render with a NavigationContainer thus I am not mocking anything in react-navigation, hence I can spy. If you don't do that, and you're looking to truly mock navigation, this won't work.

FWIW, I would recommend trying this approach first, as you can then allow much more of your code to be tested properly, as it would get used. e.g. For my CaptureLocationScreen which is in a Stack inside a modal.

render(
  <NavigationContainer>
    <RootStack.Navigator>
      <RootStack.Group screenOptions={{ presentation: 'modal', }}>
        <RootStack.Screen
          name="CaptureLocation"
          component={CaptureLocationScreen}
          options={({ navigation }: RootStackScreenProps<'CaptureLocation'>) => ({
            headerTitle: 'Add new location',
            headerLeft: () => (<CloseButton onPressed={navigation.goBack} />),
            headerRight: () => (<AcceptButton />)
          })} />
      </RootStack.Group>
    </RootStack.Navigator>
  </NavigationContainer>);

References

https://reactnavigation.org/docs/navigation-actions/

Lundberg answered 2/2, 2023 at 3:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.