# next-router-mock

> Mock implementation of the Next.js Router

Latest version **1.0.5** (published 2025-12-31) · MIT license · 0 weekly downloads

## Install

```sh
npm install next-router-mock
pnpm add next-router-mock
yarn add next-router-mock
bun add next-router-mock
```

## Health

**Score 65/100 (B)** — status: stable.

Positive: has types; esm support; no vulnerabilities; has provenance; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.0.5 |
| Published | 2025-12-31 |
| First published | 2021-01-10 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 163.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 423 |
| Maintainers | scott-rippey |
| Keywords | react, next, next.js, nextjs, router, mock, test, testing |

## Links

- npm: https://www.npmjs.com/package/next-router-mock
- Repository: https://github.com/scottrippey/next-router-mock
- Homepage: https://github.com/scottrippey/next-router-mock#readme
- Issues: https://github.com/scottrippey/next-router-mock/issues
- npm.io page: https://npm.io/package/next-router-mock

## Alternatives

- [duck](https://npm.io/package/duck.md) — 4.2M weekly downloads
- [ava](https://npm.io/package/ava.md) — 560.2K weekly downloads
- [storybook-addon-module-mock](https://npm.io/package/storybook-addon-module-mock.md) — 71.7K weekly downloads
- [vest](https://npm.io/package/vest.md) — 50.1K weekly downloads
- [@ethereum-waffle/mock-contract](https://npm.io/package/@ethereum-waffle/mock-contract.md) — 40.0K weekly downloads

## Recent versions

- 1.0.5 (latest) — 2025-12-31
- 1.0.4 — 2025-10-29
- 1.0.3 — 2025-10-29
- 1.0.2 — 2025-05-12
- 1.0.1 — 2025-05-09
- 1.0.0 — 2025-05-09
- 0.9.13 — 2024-03-28
- 0.9.12 — 2024-02-06
- 0.9.11 — 2023-12-23
- 0.9.10 — 2023-09-25
- 0.9.9 — 2023-08-13
- 0.9.8 — 2023-08-09
- 0.9.7 — 2023-06-22
- 0.9.6 — 2023-06-09
- 0.9.5 — 2023-06-09
- … 42 more at https://npm.io/package/next-router-mock/versions

## README

# `next-router-mock`

An implementation of the Next.js Router that keeps the state of the "URL" in memory (does not read or write to the
address bar). Useful in **tests** and **Storybook**.
Inspired by [`react-router > MemoryRouter`](https://github.com/remix-run/react-router/blob/main/docs/router-components/memory-router.md).

Tested with NextJS v13, v12, v11, and v10.

Install via NPM: `npm install --save-dev next-router-mock`

For usage with `next/navigation` jump to [Usage with next/navigation Beta](#usage-with-nextnavigation-beta)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [Usage with Jest](#usage-with-jest)
  - [Jest Configuration](#jest-configuration)
  - [Jest Example](#jest-example)
- [Usage with Storybook](#usage-with-storybook)
  - [Storybook Configuration](#storybook-configuration)
  - [Storybook Example](#storybook-example)
- [Compatibility with `next/link`](#compatibility-with-nextlink)
  - [Example: `next/link` with React Testing Library](#example-nextlink-with-react-testing-library)
  - [Example: `next/link` with Enzyme](#example-nextlink-with-enzyme)
  - [Example: `next/link` with Storybook](#example-nextlink-with-storybook)
- [Dynamic Routes](#dynamic-routes)
- [Sync vs Async](#sync-vs-async)
- [Supported Features](#supported-features)
  - [Not yet supported](#not-yet-supported)
- [Usage with next/navigation Beta](#usage-with-nextnavigation-beta)
  - [Usage with Jest](#usage-with-jest-1)
    - [Jest Configuration](#jest-configuration-1)
    - [Jest Example](#jest-example-1)
    - [Supported](#supported)
    - [Not supported yet](#not-supported-yet)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# Usage with Jest

### Jest Configuration

For unit tests, the `next-router-mock` module can be used as a drop-in replacement for `next/router`:

```js
jest.mock("next/router", () => require("next-router-mock"));
```

You can do this once per spec file, or you can [do this globally using `setupFilesAfterEnv`](https://jestjs.io/docs/configuration/#setupfilesafterenv-array).

### Jest Example

In your tests, use the router from `next-router-mock` to set the current URL and to make assertions.

```jsx
import { useRouter } from "next/router";
import { render, screen, fireEvent } from "@testing-library/react";
import mockRouter from "next-router-mock";

jest.mock("next/router", () => jest.requireActual("next-router-mock"));

const ExampleComponent = ({ href = "" }) => {
  const router = useRouter();
  return <button onClick={() => router.push(href)}>The current route is: "{router.asPath}"</button>;
};

describe("next-router-mock", () => {
  it("mocks the useRouter hook", () => {
    // Set the initial url:
    mockRouter.push("/initial-path");

    // Render the component:
    render(<ExampleComponent href="/foo?bar=baz" />);
    expect(screen.getByRole("button")).toHaveTextContent('The current route is: "/initial-path"');

    // Click the button:
    fireEvent.click(screen.getByRole("button"));

    // Ensure the router was updated:
    expect(mockRouter).toMatchObject({
      asPath: "/foo?bar=baz",
      pathname: "/foo",
      query: { bar: "baz" },
    });
  });
});
```

# Usage with Storybook

### Storybook Configuration

Globally enable `next-router-mock` by adding the following webpack alias to your Storybook configuration.

In `.storybook/main.js` add:

```js
module.exports = {
  webpackFinal: async (config, { configType }) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      "next/router": "next-router-mock",
    };
    return config;
  },
};
```

This ensures that all your components that use `useRouter` will work in Storybook. If you also need to test `next/link`, please see the section [Example: **`next/link` with Storybook**](#example-nextlink-with-storybook).

### Storybook Example

In your individual stories, you might want to mock the current URL (eg. for testing an "ActiveLink" component), or you might want to log `push/replace` actions. You can do this by wrapping your stories with the `<MemoryRouterProvider>` component.

```jsx
// ActiveLink.story.jsx
import { action } from "@storybook/addon-actions";
import { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider/next-13";
import { ActiveLink } from "./active-link";

export const ExampleStory = () => (
  <MemoryRouterProvider url="/active" onPush={action("router.push")}>
    <ActiveLink href="/example">Not Active</ActiveLink>
    <ActiveLink href="/active">Active</ActiveLink>
  </MemoryRouterProvider>
);
```

> Be sure to import from **a matching Next.js version**:
>
> ```
> import { MemoryRouterProvider }
>   from 'next-router-mock/MemoryRouterProvider/next-13.5';
> ```
>
> Choose from `next-13.5`, `next-13`, `next-12`, or `next-11`.

The `MemoryRouterProvider` has the following optional properties:

- `url` (`string` or `object`) sets the current route's URL
- `async` enables async mode, if necessary (see "Sync vs Async" for details)
- Events:
  - `onPush(url, { shallow })`
  - `onReplace(url, { shallow })`
  - `onRouteChangeStart(url, { shallow })`
  - `onRouteChangeComplete(url, { shallow })`

# Compatibility with `next/link`

To use `next-router-mock` with `next/link`, you must use a `<MemoryRouterProvider>` to wrap the test component.

### Example: `next/link` with React Testing Library

When rendering, simply supply the option `{ wrapper: MemoryRouterProvider }`

```jsx
import { render } from "@testing-library/react";
import NextLink from "next/link";

import mockRouter from "next-router-mock";
import { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";

it("NextLink can be rendered", () => {
  render(<NextLink href="/example">Example Link</NextLink>, { wrapper: MemoryRouterProvider });
  fireEvent.click(screen.getByText("Example Link"));
  expect(mockRouter.asPath).toEqual("/example");
});
```

### Example: `next/link` with Enzyme

When rendering, simply supply the option `{ wrapperComponent: MemoryRouterProvider }`

```jsx
import { shallow } from "enzyme";
import NextLink from "next/link";

import mockRouter from "next-router-mock";
import { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";

it("NextLink can be rendered", () => {
  const wrapper = shallow(<NextLink href="/example">Example Link</NextLink>, {
    wrapperComponent: MemoryRouterProvider,
  });

  wrapper.find("a").simulate("click");

  expect(mockRouter.asPath).to.equal("/example");
});
```

### Example: `next/link` with Storybook

In Storybook, you must wrap your component with the `<MemoryRouterProvider>` component (with optional `url` set).

```jsx
// example.story.jsx
import NextLink from "next/link";
import { action } from "@storybook/addon-actions";

import { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider/next-13.5";

export const ExampleStory = () => (
  <MemoryRouterProvider url="/initial">
    <NextLink href="/example">Example Link</NextLink>
  </MemoryRouterProvider>
);
```

This can be done inline (as above).  
It can also be implemented as a `decorator`, which can be per-Story, per-Component, or Global (see [Storybook Decorators Documentation](https://storybook.js.org/docs/react/writing-stories/decorators) for details).  
Global example:

```
// .storybook/preview.js
import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider';

export const decorators = [
  (Story) => <MemoryRouterProvider><Story /></MemoryRouterProvider>
];
```

# Dynamic Routes

By default, `next-router-mock` does not know about your dynamic routes (eg. files like `/pages/[id].js`).
To test code that uses dynamic routes, you must add the routes manually, like so:

```typescript
import mockRouter from "next-router-mock";
import { createDynamicRouteParser } from "next-router-mock/dynamic-routes";

mockRouter.useParser(
  createDynamicRouteParser([
    // These paths should match those found in the `/pages` folder:
    "/[id]",
    "/static/path",
    "/[dynamic]/path",
    "/[...catchAll]/path",
  ])
);

// Example test:
it("should parse dynamic routes", () => {
  mockRouter.push("/FOO");
  expect(mockRouter).toMatchObject({
    pathname: "/[id]",
    query: { id: "FOO" },
  });
});
```

# Sync vs Async

By default, `next-router-mock` handles route changes synchronously. This is convenient for testing, and works for most
use-cases.  
However, Next normally handles route changes asynchronously, and in certain cases you might actually rely on that
behavior. If that's the case, you can use `next-router-mock/async`. Tests will need to account for the async behavior
too; for example:

```jsx
it("next/link can be tested too", async () => {
  render(
    <NextLink href="/example?foo=bar">
      <a>Example Link</a>
    </NextLink>
  );
  fireEvent.click(screen.getByText("Example Link"));
  await waitFor(() => {
    expect(singletonRouter).toMatchObject({
      asPath: "/example?foo=bar",
      pathname: "/example",
      query: { foo: "bar" },
    });
  });
});
```

# Supported Features

- `useRouter()`
- `withRouter(Component)`
- `router.push(url, as?, options?)`
- `router.replace(url, as?, options?)`
- `router.route`
- `router.pathname`
- `router.asPath`
- `router.query`
- Works with `next/link` (see Jest notes)
- `router.events` supports:
  - `routeChangeStart(url, { shallow })`
  - `routeChangeComplete(url, { shallow })`
  - `hashChangeStart(url, { shallow })`
  - `hashChangeComplete(url, { shallow })`

## Not yet supported

PRs welcome!  
These fields just have default values; these methods do nothing.

- `router.isReady`
- `router.basePath`
- `router.isFallback`
- `router.isLocaleDomain`
- `router.locale`
- `router.locales`
- `router.defaultLocale`
- `router.domainLocales`
- `router.prefetch()`
- `router.back()`
- `router.beforePopState(cb)`
- `router.reload()`
- `router.events` not implemented:
  - `routeChangeError`
  - `beforeHistoryChange`

# Usage with next/navigation Beta

## Usage with Jest

### Jest Configuration

For unit tests, the `next-router-mock/navigation` module can be used as a drop-in replacement for `next/navigation`:

```js
jest.mock("next/navigation", () => require("next-router-mock/navigation"));
```

You can do this once per spec file, or you can [do this globally using `setupFilesAfterEnv`](https://jestjs.io/docs/configuration/#setupfilesafterenv-array).

### Jest Example

In your tests, use the router from `next-router-mock` to set the current URL and to make assertions.

```jsx
import mockRouter from "next-router-mock";
import { render, screen, fireEvent } from "@testing-library/react";
import { usePathname, useRouter } from "next/navigation";

jest.mock("next/navigation", () => jest.requireActual("next-router-mock/navigation"));

const ExampleComponent = ({ href = "" }) => {
  const router = useRouter();
  const pathname = usePathname();
  return <button onClick={() => router.push(href)}>The current route is: {pathname}</button>;
};

describe("next-router-mock", () => {
  it("mocks the useRouter hook", () => {
    // Set the initial url:
    mockRouter.push("/initial-path");

    // Render the component:
    render(<ExampleComponent href="/foo?bar=baz" />);
    expect(screen.getByRole("button")).toHaveTextContent("The current route is: /initial-path");

    // Click the button:
    fireEvent.click(screen.getByRole("button"));

    // Ensure the router was updated:
    expect(mockRouter).toMatchObject({
      asPath: "/foo?bar=baz",
      pathname: "/foo",
      query: { bar: "baz" },
    });
  });
});
```

### Supported

- useRouter
- usePathname
- useParams
- useSearchParams

### Not supported yet

- Storybook
- useSelectedLayoutSegment, useSelectedLayoutSegments
- non-hook utils in next/navigation

---
_Source: https://npm.io/package/next-router-mock · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
