Search code examples
react-nativeunit-testingjestjsexpo

Jest testing React-Native component that used useRouter() from expo-router getting error


I am trying to test a component that is accesing useRouter from expo-router

My Component:

import { useRouter } from 'expo-router'

const CustomComponent: React.FC<Props> = () => {
  const router = useRouter()

  const onPress = () => {
    router.replace(PATHS.DASHBOARD)
  }

  return <HCard pressAction={onPress} title={'title'} />
}

The test file:


describe('CustomComponent', () => {
  it('should render CustomComponent correctly', () => {
    const wrapper = renderWithProvider(<CustomComponent />)
    expect(wrapper.getByText('title')).toBeOnTheScreen()
  })
})

I am getting this error: Couldn't find a navigation object. Is your component inside NavigationContainer?

I understand what the error suggests, but I do not know how to provide that NavigationContainer, since it is not part of expo-router. Also, I have mocked the useRouter, but got the same error

Later edit Here is the renderWithProvider:

export const renderWithProvider = (children: JSX.Element): RenderResult => {
  const inset = {
    frame: { x: 0, y: 0, width: 0, height: 0 },
    insets: { top: 0, left: 0, right: 0, bottom: 0 },
  }

  return render(<NativeBaseProvider initialWindowMetrics={inset}>{children}</NativeBaseProvider>)
}

Solution

  • I've built this util to help me with this error. Basically when you are mounting your component inside a jest suite, it doesn't have the navigation stack necessary for useRouter to work.

    import { NavigationContainer } from "@react-navigation/native";
    import { createNativeStackNavigator } from "@react-navigation/native-stack";
    
    type NavigationMockProps = {
      controller: ComponentType<any>;
      params?: any;
    };
    export const NavigationMock = ({ controller, params }: NavigationMockProps) => {
      const stack = createNativeStackNavigator<any>();
    
      return (
        <NavigationContainer independent>
          <stack.Navigator initialRouteName="TestRoute">
            <stack.Screen
              name="TestRoute"
              component={controller}
              initialParams={params}
              options={{ header: () => null }}
            />
          </stack.Navigator>
        </NavigationContainer>
      );
    };
    

    Then, you can use it like this:

    describe('CustomComponent', () => {
      it('should render CustomComponent correctly', () => {
        const wrapper = render(
           <NavigationMock controller={CustomComponent} params={params} />
        );
        expect(wrapper.getByText('title')).toBeOnTheScreen();
      })
    })