VOOZH about

URL: https://blog.logrocket.com/testing-react-router-usenavigate-hook-react-testing-library/

⇱ Testing the React Router useNavigate Hook with React Testing Library - LogRocket Blog


2023-05-04
1472
#react
Paul Cowan
21176
👁 Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

Editor’s note: This article was last updated by Rahul Chhodde on 4 May 2023 to include information the React fireEvent and userEvent Hooks, as well as testing the React query parameters.

👁 Testing The React Router UseNavigate Hook With React Testing Library

React Testing Library is a lightweight solution that provides a virtual DOM to interact with and verify the behavior of a React component. Rather than work like a test runner, this testing library requires a tool like Jest to implement automated testing in React.

Using React Testing Library, popularly known as RTL in the community, is the recommended way to test your apps because it is actively maintained, well-documented, fast, flexible, and powerful enough to write comprehensive and reliable tests.

From React 18 onwards, React Hook Testing Library is included in the React Testing Library, and you can access it only through RTL. Learn more here.

In this article, we will cover testing scenarios of the useNavigate Hook from React Router 6 with RTL and Jest. We will unit test the routes and briefly discuss the different features that RTL offers to simplify the process of making components route-aware.

Jump ahead:

🚀 Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Understanding the useNavigate Hook

React Router v6+ now uses the useNavigate Hook instead of the useHistory Hook. You can use useNavigate to go to a specific path or move back and forth in the browser history.

To add routes to your React app, you need to install the react-router-dom package. Once you have installed the package, you can import the Route component from it. The Route component takes two props: path and component. The path prop is the URL path that the route should match, and the component prop is the component that should be rendered when the route matches.

For example, the following code would add a route that matches the / path and renders the Home component:

import { Routes, Route } from "react-router-dom";
import { Home } from "./components/Home";
import { About } from "./components/About";

function App() {
 return (
 <>
 <Routes>
 <Route path="/" element={<Home />} />
 <Route path="/about" element={<About />} />
 </Routes>
 </>
 );
}
export default App;

Let’s implement the useNavigate Hook. The example below shows how easy it is to navigate to other routes by using the useNavigate Hook:

import { useNavigate } from "react-router-dom";

function HomeButton() {
 const navigate = useNavigate();

 function handleClick() {
 navigate("/home");
 }

 return (
 <button type="button" onClick={handleClick}>
 Go home
 </button>
 );
}

Here is the live, working version of our project, which also includes the rest of the examples we covered in this article. See it on CodeSandbox here.

If you add { replace: true } as a second argument when using the useNavigate Hook, it works like the older history.replace method. To move back and forth in the history stack, use the following approach:

function HomeButton() {
 const navigate = useNavigate();

 const goBack() => navigate(-1);
 const goForward() => navigate(1);
}

Testing the useNavigate Hook with jest.mock

Avoid using jest.mock to test React routes, as React Testing Library offers various methods to test routes without mocking. You can use the render method to isolate a route, the getBy* method to locate elements in the rendered page, and the fireEvent and userEvent Hooks to trigger different events.

Testing React routes and the useNavigate Hook

As discussed before, React Router 6 and above now uses the useNavigate Hook instead of the useHistory Hook. You can no longer set the history prop to the router anymore. The history API is buggy and must have been discontinued in the newer version of React in favor of simplifying the complicated routing practices, so relying on it for routing is not a good idea.

Here’s a straightforward application to show you how to test routes with useNavigate. The application has different route components, and we used RTL and Jest features to test each one:

import { fireEvent, render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { MemoryRouter, BrowserRouter } from "react-router-dom";
import { About } from "./About";

describe("Demonstrating some useNavigate() tests ", () => {
 it("Renders the About component", () => {
 const { getByText } = render(
 <BrowserRouter>
 <About />
 </BrowserRouter>
 );

 const button = getByText(/contact us/i);
 expect(button).toBeInTheDocument();
 fireEvent.click(button);
 });
});

The above is a test component for the “About” section of our app. Keep in mind that all test components must be in the same directory as the original component so that Jest can detect our tests.

We use the describe and it methods from Jest to describe our tests and add some sample assertions. To locate an element with a specific text fragment from the rendered component, we use the RTL getByText utility. If the text fragment is not found, you’ll see an error while testing.

Next, we use fireEvent to click the selected button element. You can customize these tests further to fit your own needs.

Testing query parameters with useLocation

We now know how to test the regular React routes with RTL and Jest. Let’s test a route with query parameters with the help of the useLocation Hook.

We can grab the current URL with the useLocation Hook, then get the query string and extract the value from the query parameter using URLSearchParams, which is part of the Web API and Node.js API:

import { useLocation } from "react-router-dom";

const QueryParamComponent = () => {
 const location = useLocation();
 const id = new URLSearchParams(location.search).get("id");

 return (
 <div>
 <h1>Query Parameter Component</h1>
 <p>ID: {id}</p>
 </div>
 );
};
export default QueryParamComponent;

After extracting the value of the id query parameter from the URL, we added it to the resulting DOM element of this component. Now, let’s add a test for this:

import { render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import QueryParamComponent from "./QueryParamComponent";
import "@testing-library/jest-dom";

describe("MyComponent", () => {
 it("renders the ID query parameter from the URL", () => {
 render(
 <MemoryRouter initialEntries={["/qpc?id=123"]}>
 <QueryParamComponent />
 </MemoryRouter>
 );
 expect(screen.getByText("ID: 123")).toBeInTheDocument();
 });
});

In the above code, we used MemoryRouter to create a mock router that we could use to test the behavior of the QueryParamComponent when it receives a query parameter through the location prop. We set its initial path to /query with an id query parameter so that our component would receive this information when it was rendered. Again, you can see this for yourself in the CodeSandbox demo’s tests.



Using the fireEvent and userEvent methods

The fireEvent method can dispatch any DOM event to an element, which helps test how components respond to events. For instance, you can use it to test a button that logs an input field’s value when clicked.

In contrast, userEvent is a simpler method that mimics how users interact with a component. This is helpful when testing components designed for humans, such as a login form:

...
describe("Login component", () => {
 it("Filling details and clicking buttons in a login gorm", async () => {
 render(
 <BrowserRouter>
 <Login />
 </BrowserRouter>
 );

 userEvent.type(screen.getByLabelText("Username"), "hello");
 userEvent.type(screen.getByLabelText("Password"), "123");
 userEvent.click(screen.getByRole("button", { name: "Submit" }));
 });
});

To use the userEvent object, you need to install the @testing-library/user-event package as an additional dependency.


Over 200k developers use LogRocket to create better digital experiences

👁 Image
Learn more →

Testing hooks with React Testing Library

As I mentioned earlier, you don’t need to use the @testing-library/react-hooks library anymore with React 18 and above. The RTL now includes built-in methods for testing hooks.

It’s fairly easy to test different hooks using the RTL built-in methods only. Here is an example of how to test a custom hook created with useState, demonstrating a dynamic count component that increments with a button click:

describe("CountComponent", () => {
 it("SHOULD render the expected Count Component", () => {
 const { getByText } = render(
 <BrowserRouter>
 <CountComponent />
 </BrowserRouter>
 );
 const heading = getByText(/the count component/i);
 const count = getByText(/the count is 0/i);

 expect(heading).toBeInTheDocument();
 expect(count).toBeInTheDocument();
 });

 it("SHOULD increment the count when the button is CLICKED", () => {
 const { getByText } = render(
 <BrowserRouter>
 <CountComponent />
 </BrowserRouter>
 );

 const button = getByText(/increment Count/i);
 const count = getByText(/the count is 0/i);
 fireEvent.click(button);
 expect(count).toHaveTextContent(/the count is 1/i");
 });
});

This component and its test are only available in the CodeSandbox example.

Conclusion

With the ever-changing React ecosystem, there are new tools available to help you write better tests. I don’t recommend using Jest mocks to test routes, as this can give the illusion of testing without actually testing anything.

In this article, we explored how to test the useNavigate Hook that was introduced in React Router v6. I hope you enjoyed this article, and feel free to leave a comment if you have any questions. Happy testing!

Get set up with LogRocket's modern React error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side

    $ npm i --save logrocket 
    
    // Code:
    
    import LogRocket from 'logrocket'; 
    LogRocket.init('app/id');
     
    // Add to your HTML:
    
    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
     
  3. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin
Get started now
👁 Image
👁 Image
👁 Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

👁 Image
Emmanuel John
Jun 17, 2026 ⋅ 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

👁 Image
Chizaram Ken
Jun 16, 2026 ⋅ 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension — no new framework required.

👁 Image
Ikeh Akinyemi
Jun 12, 2026 ⋅ 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo — with email/password login, Google OAuth, session persistence, and protected routes.

👁 Image
Chinwike Maduabuchi
Jun 9, 2026 ⋅ 13 min read
View all posts

Hey there, want to help make our blog better?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now