Fixing NextRouter Was Not Mounted in Next.js Testing
- 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.

Why Does the Error Occur?
Here are the main reasons why this error happens during testing:
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.
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.
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
The "NextRouter was not mounted" error occurs when the Next.js router is not available during component testing.
The useRouter hook and next/link component depend on RouterContext, which needs to be mocked during tests.
Mocking the router in Jest or setting up a custom mount command in Cypress solves the error.
Always provide the RouterContext when testing components that rely on routing.
Separate routing logic from core component functionality to make components easier to test.
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.
Comments