React Router V6 - useNavigate() may be used only in the context of a <Router> component
Asked Answered
C

3

12

I have installed react-router-domV6. I am having the above error when I run my very basic test using Jest-Enzyme:

expect(shallow(<CustomerListTable customers={mockCustomers} />).length).toEqual(1);

I already came across this similar issue mentioned here, but I am already doing the provided answers. Even tried doing the import { BrowserRouter as Router } from "react-router-dom";. What am I missing here?

index.js

import React, { Suspense } from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { StrictMode } from "react";
import { BrowserRouter } from "react-router-dom";
...

ReactDOM.render(
  <StrictMode>
          ...
            <BrowserRouter>
              <AuthProvider>
                <App />
              </AuthProvider>
            </BrowserRouter>
          ...
  </StrictMode>,
  document.getElementById("root")
);

App.js

import React from "react";
import { useRoutes } from "react-router-dom";
import Routing from "./routes";
import useAuth from "./hooks/useAuth";
import { CreateCustomTheme } from "./theme";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import useSettings from "./hooks/useSettings";
import useScrollReset from "./hooks/useScrollReset";
import SplashScreen from "./components/splashScreen/SplashScreen";

const App = () => {
  const content = useRoutes(Routing());
  const { settings } = useSettings();
  const auth = useAuth();

  useScrollReset();

  const theme = CreateCustomTheme({
    direction: settings.direction,
    responsiveFontSizes: settings.responsiveFontSizes,
    roundedCorners: settings.roundedCorners,
    theme: settings.theme,
  });
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      {auth.isInitialized ? content : <SplashScreen />}
    </ThemeProvider>
  );
};

export default App;
Carlin answered 19/11, 2021 at 4:35 Comment(0)
S
14

It seems the CustomerListTable component you are testing in isolation doesn't have access to a routing context it's expecting as when it's rendered in the app normally. It's completely normal to need to wrap components when testing them with providers (redux, themes/styling, localization, routing, etc...) that are providing specific React Context values the component is accessing, typically via React hooks.

For the unit test you should wrap the component with the providers it's expecting to have.

expect(shallow(
  <BrowserRouter>
    <CustomerListTable customers={mockCustomers} />
  </BrowserRouter>
).length).toEqual(1);

It's been a long time since I've used Enzyme, so I'm not certain the shallow render will still work, but if it doesn't then swap to the full mount test renderer.

Sidestep answered 19/11, 2021 at 5:9 Comment(0)
E
25

To fix this issue, you can direct mock your useNavigate() like this after all the imports for the file in which you are writing the test case:-

const mockUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
   ...jest.requireActual('react-router-dom'),
  useNavigate: () => mockUsedNavigate,
}));
Escrow answered 10/12, 2021 at 8:43 Comment(0)
S
14

It seems the CustomerListTable component you are testing in isolation doesn't have access to a routing context it's expecting as when it's rendered in the app normally. It's completely normal to need to wrap components when testing them with providers (redux, themes/styling, localization, routing, etc...) that are providing specific React Context values the component is accessing, typically via React hooks.

For the unit test you should wrap the component with the providers it's expecting to have.

expect(shallow(
  <BrowserRouter>
    <CustomerListTable customers={mockCustomers} />
  </BrowserRouter>
).length).toEqual(1);

It's been a long time since I've used Enzyme, so I'm not certain the shallow render will still work, but if it doesn't then swap to the full mount test renderer.

Sidestep answered 19/11, 2021 at 5:9 Comment(0)
E
5

Using "react-router-dom": "^6.12.0",

For unit testing I solved the issue like this:

  1. import memory router:
import { MemoryRouter as Router } from "react-router-dom";
  1. Wrap the component with the router
<Router>
    <CustomerListTable customers={mockCustomers} />
</Router>
Espinosa answered 26/6, 2023 at 13:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.