Reputation: 273
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 ?
Upvotes: 25
Views: 27000
Reputation: 1
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.
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>);
https://reactnavigation.org/docs/navigation-actions/
Upvotes: 0
Reputation: 743
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.
Upvotes: 57
Reputation: 374
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.
Upvotes: 6
Reputation: 271
jest.mock("@react-navigation/native", () => {
const actualNav = jest.requireActual("@react-navigation/native")
return {
...actualNav,
useFocusEffect: () => jest.fn(),
useNavigation: () => ({
navigate: jest.fn(),
}),
}
})
Upvotes: 5