top of page
90s theme grid background

Fixing NextRouter Was Not Mounted in Next.js Testing

  • Writer: Gunashree RS
    Gunashree RS
  • Sep 19, 2024
  • 7 min read

When testing Next.js applications, especially when using libraries like Cypress or Jest, you may encounter an error message: "NextRouter was not mounted". This error typically arises when trying to render or test components that rely on Next.js routing features, such as useRouter, next/link, or next/router. This guide will walk you through what this error means, why it happens, and most importantly, how to fix it.


In this detailed guide, we will cover:

  • What the "NextRouter was not mounted" error is

  • Why the error occurs during testing

  • Solutions for fixing the error in your Next.js tests

  • Best practices for structuring tests with Next.js components that depend on routing

  • Tips for mocking and stubbing the NextRouter

  • How to test useRouter and next/link effectively

By the end of this article, you’ll have a complete understanding of how to resolve the "NextRouter was not mounted" error, ensuring your Next.js tests run smoothly.



What Is the "NextRouter Was Not Mounted" Error?

The "NextRouter was not mounted" error occurs when Next.js components that depend on Next.js routing features are tested without properly setting up the RouterContext. Next.js uses a global router to handle page navigation in Single Page Applications (SPA), and components that rely on routing features (such as useRouter and next/link) need access to the global router context.


In component testing scenarios, this global router is typically not available unless explicitly provided. As a result, components that require it fail with the "NextRouter was not mounted" error.


Next.js Testing

Why Does the Error Occur?

Here are the main reasons why this error happens during testing:

  1. RouterContext Is Not Available: The Next.js router isn’t automatically set up in test environments. Unlike production, where routing works seamlessly through Next.js's internal mechanisms, testing environments don’t mount the router unless you do it explicitly.

  2. Components Depending on useRouter: If your components use the useRouter hook to access routing information, but the router is not provided in the test, the component will throw the "NextRouter was not mounted" error.

  3. Testing Tools Don’t Include Router Logic: Testing tools like Cypress or Jest do not automatically include the Next.js routing context, so manual setup or mocking is required.



Understanding How Next.js Router Works

Before diving into solutions, it’s important to understand the basic mechanics of Next.js routing.


1. RouterContext

At the core of Next.js’s routing system is RouterContext, a global object that holds all the routing information, such as the current path, query parameters, and more. Components like next/link and useRouter rely on this context to function.


2. useRouter Hook

The useRouter hook allows components to access the router object and retrieve the current path, push new routes, and more. However, during tests, this hook will throw an error if the router is not mounted.


3. next/link Component

The next/link component simplifies navigation in Next.js applications. It provides a declarative way to create links between pages. Like useRouter, it also depends on the Next.js router, and if not properly mocked during testing, it will fail with the "NextRouter was not mounted" error.



How to Fix the "NextRouter Was Not Mounted" Error

Here are various solutions for resolving the "NextRouter was not mounted" error in your tests:


1. Mocking the Router in Tests

One of the most straightforward ways to solve this issue is to mock the Next.js router in your tests. Mocking provides a fake implementation of the router so that components relying on useRouter or next/link can access routing functions without throwing errors.


Mocking useRouter in Jest

Here’s how to mock the useRouter hook using Jest:

javascript

import { useRouter } from 'next/router';

jest.mock('next/router', () => ({
  useRouter: jest.fn(),
}));

describe('MyComponent Tests', () => {
  beforeEach(() => {
    useRouter.mockReturnValue({
      route: '/test-route',
      pathname: '/test-pathname',
      query: { id: '123' },
      asPath: '/test-route',
    });
  });

  it('should render without crashing', () => {
    // Your component test here
  });
});

In this setup, we mock the useRouter hook to return specific values (like the route, pathname, and query parameters) that your component might rely on.


Mocking next/link in Jest

If your component uses next/link, you can mock it like this:

javascript

import Link from 'next/link';

jest.mock('next/link', () => {
  return ({ children, href }) => <a href={href}>{children}</a>;
});

This simple mock ensures that next/link works as expected in your tests without throwing any errors related to the router not being mounted.


2. Using Custom Router Setup in Cypress

For Cypress component tests, you can create a custom mount command that sets up the NextRouter and RouterContext. Here’s an example of how to do it:

javascript

import { RouterContext } from 'next/dist/shared/lib/router-context'; // Import RouterContext
import { mount } from 'cypress/react';

Cypress.Commands.add('nextMount', (component, options = {}) => {
  const router = {
    route: '/',
    pathname: '/',
    query: {},
    asPath: '/',
    push: cy.stub().as('routerPush'), // Mock push function
    prefetch: cy.stub().as('routerPrefetch'),
  };

  return mount(
    <RouterContext.Provider value={router}>
      {component}
    </RouterContext.Provider>
  );
});

This custom nextMount command ensures that the router is available during your Cypress component tests. You can also mock router functions like push and prefetch as needed.


3. Manually Mounting RouterContext in Tests

If you’re not using Cypress or Jest, and want a solution that works across different environments, you can manually mount the RouterContext in your test files:

javascript

import { RouterContext } from 'next/dist/shared/lib/router-context';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent';

const mockRouter = {
  route: '/',
  pathname: '/',
  query: {},
  asPath: '/',
  push: jest.fn(),
};

describe('MyComponent Test', () => {
  it('renders correctly with router context', () => {
    render(
      <RouterContext.Provider value={mockRouter}>
        <MyComponent />
      </RouterContext.Provider>
    );
  });
});

This approach works well with libraries like React Testing Library and ensures that your components can access the Next.js router without encountering the "NextRouter was not mounted" error.



Best Practices for Testing Next.js Components with Routing

To avoid issues like "NextRouter was not mounted" in the future, it’s important to follow best practices when testing components that rely on Next.js routing.


1. Keep Routing Logic Separate

Try to keep routing logic separate from the core functionality of your components. This separation makes it easier to test components in isolation without needing to mock the router every time.


2. Use Mocking for Router-Dependent Components

For components that depend heavily on useRouter or next/link, always mock the router in your tests. This ensures that your tests remain fast and isolated, without depending on actual routing behavior.


3. Minimize Router Usage in Small Components

Smaller components that don’t require routing features shouldn’t depend on useRouter or next/link. If you must use these features, consider passing the necessary routing information as props to the component.


4. Use Page Components as Data Wrappers

Use Page Components in Next.js as data wrappers, passing props to pure React components. This way, your core components remain testable without complex routing logic.



Common Pitfalls When Testing Next.js Router-Dependent Components

Even with the right setup, some challenges may arise when testing Next.js components that depend on routing.


1. Not Mocking Router Functions

Ensure that router functions like push, replace, and prefetch are properly mocked. If these functions are undefined during the test, your component may fail.


2. Forgetting to Provide RouterContext

If you’re using useRouter in your component but forget to provide the RouterContext during tests, the "NextRouter was not mounted" error will occur. Always ensure that the context is provided before rendering your component.


3. Overcomplicating Router Mocks

While mocking the router, keep the mock implementation simple. Avoid overcomplicating the mock with unnecessary logic, as this can lead to maintenance challenges down the line.



Conclusion

The "NextRouter was not mounted" error is a common issue that developers face when testing Next.js components that rely on routing features. Fortunately, with the right strategies—such as mocking useRouter and next/link, setting up custom commands in Cypress, and manually providing RouterContext—you can easily fix this error and create reliable tests for your Next.js components.

By following the best practices outlined in this guide, you’ll be able to ensure that your tests run smoothly, and your components perform as expected in both test and production environments.



Key Takeaways

  1. The "NextRouter was not mounted" error occurs when the Next.js router is not available during component testing.

  2. The useRouter hook and next/link component depend on RouterContext, which needs to be mocked during tests.

  3. Mocking the router in Jest or setting up a custom mount command in Cypress solves the error.

  4. Always provide the RouterContext when testing components that rely on routing.

  5. Separate routing logic from core component functionality to make components easier to test.

  6. Follow best practices like mocking router functions and using Page Components as data wrappers to minimize testing issues.




FAQs About "NextRouter Was Not Mounted"


1. What does "NextRouter was not mounted" mean?

It means that the Next.js router, which is required by components using useRouter or next/link, is not available in the testing environment.


2. How do I fix the "NextRouter was not mounted" error in Jest?

You can fix this error by mocking the useRouter hook using jest.mock and providing mock values for the router object.


3. Can I test Next.js components without using the router?

Yes, if your component doesn’t rely on routing, you don’t need the router. However, for router-dependent components, you’ll need to mock or provide the router.


4. How do I mock next/link in tests?

You can mock next/link by replacing it with a simple <a> tag that renders the children and href attribute.


5. Why do I need to mock the router in tests?

Next.js components rely on a global router object that’s only available in a running Next.js app. In test environments, you need to mock this router to simulate routing behavior.


6. What are the benefits of using Cypress for testing Next.js components?

Cypress allows for real-time testing in the browser, making it easier to simulate user interactions and test how your components respond to routing changes.


7. How do I mock useRouter for multiple tests?

You can mock useRouter in your test setup file to ensure the mock is applied across multiple tests, simplifying the process.


8. Can I test the next/router with Cypress?

Yes, you can set up a custom Cypress command to mock RouterContext and test components that depend on the next/router.



External Sources


Comments


bottom of page