to override the singleton, if needed
22 | useMemoryRouter(memoryRouter)
23 | );
24 | };
25 |
26 | // Export the `withRouter` HOC:
27 | export const withRouter = (
28 | ComposedComponent: NextComponentType
29 | ) => {
30 | return withMemoryRouter(useRouter, ComposedComponent);
31 | };
32 |
--------------------------------------------------------------------------------
/src/dynamic-routes/createDynamicRouteParser.test.tsx:
--------------------------------------------------------------------------------
1 | import { MemoryRouter } from "../MemoryRouter";
2 | import { createDynamicRouteParser } from "./next-12";
3 | import { expectMatch } from "../../test/test-utils";
4 |
5 | describe("dynamic routes", () => {
6 | let memoryRouter: MemoryRouter;
7 | beforeEach(() => {
8 | memoryRouter = new MemoryRouter();
9 | });
10 |
11 | it("when dynamic path registered will parse variables from slug", () => {
12 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]/attribute/[name]", "/[...slug]"]));
13 |
14 | memoryRouter.push("/entity/101/attribute/everything");
15 | expectMatch(memoryRouter, {
16 | pathname: "/entity/[id]/attribute/[name]",
17 | asPath: "/entity/101/attribute/everything",
18 | query: {
19 | id: "101",
20 | name: "everything",
21 | },
22 | });
23 | });
24 |
25 | it("when catch-all dynamic path registered will parse variables from slug", () => {
26 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]/attribute/[name]", "/[...slug]"]));
27 |
28 | memoryRouter.push("/one/two/three");
29 | expectMatch(memoryRouter, {
30 | pathname: "/[...slug]",
31 | asPath: "/one/two/three",
32 | query: {
33 | slug: ["one", "two", "three"],
34 | },
35 | });
36 | });
37 |
38 | it("when no dynamic path matches, will not parse query from slug", () => {
39 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]/attribute/[name]"]));
40 |
41 | memoryRouter.push("/one/two/three");
42 | expectMatch(memoryRouter, {
43 | pathname: "/one/two/three",
44 | asPath: "/one/two/three",
45 | query: {},
46 | });
47 | });
48 |
49 | it("when both dynamic and static path matches, will use static path", () => {
50 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]", "/entity/list"]));
51 |
52 | memoryRouter.push("/entity/list");
53 | expectMatch(memoryRouter, {
54 | pathname: "/entity/list",
55 | asPath: "/entity/list",
56 | query: {},
57 | });
58 | });
59 |
60 | it("when query param matches path param, path param will take precedence", () => {
61 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]"]));
62 |
63 | memoryRouter.push("/entity/100?id=500");
64 |
65 | expectMatch(memoryRouter, {
66 | asPath: "/entity/100?id=500",
67 | pathname: "/entity/[id]",
68 | query: { id: "100" },
69 | });
70 | });
71 |
72 | it("when slug passed in pathname, pathname should be set to route and asPath interpolated from query", () => {
73 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]"]));
74 |
75 | memoryRouter.push({ pathname: "/entity/[id]", query: { id: "42" } });
76 |
77 | expectMatch(memoryRouter, {
78 | pathname: "/entity/[id]",
79 | asPath: "/entity/42",
80 | query: { id: "42" },
81 | });
82 | });
83 |
84 | it("when slug passed in pathname with additional query params, asPath should have query string", () => {
85 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]"]));
86 |
87 | memoryRouter.push({ pathname: "/entity/[id]", query: { id: "42", filter: "abc" } });
88 |
89 | expectMatch(memoryRouter, {
90 | pathname: "/entity/[id]",
91 | asPath: "/entity/42?filter=abc",
92 | query: { id: "42", filter: "abc" },
93 | });
94 | });
95 |
96 | it("will properly interpolate catch-all routes from the pathname", () => {
97 | memoryRouter.useParser(createDynamicRouteParser(["/[...slug]"]));
98 |
99 | memoryRouter.push({ pathname: "/[...slug]", query: { slug: ["one", "two", "three"] } });
100 |
101 | expectMatch(memoryRouter, {
102 | pathname: "/[...slug]",
103 | asPath: "/one/two/three",
104 | query: { slug: ["one", "two", "three"] },
105 | });
106 | });
107 |
108 | it("with dynamic routes, will properly generate asPath when passed in query dictionary", () => {
109 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]"]));
110 |
111 | memoryRouter.push({ pathname: "/entity/100", query: { filter: "abc", max: "1000" } });
112 |
113 | expectMatch(memoryRouter, {
114 | pathname: "/entity/[id]",
115 | asPath: "/entity/100?filter=abc&max=1000",
116 | query: { id: "100", filter: "abc", max: "1000" },
117 | });
118 | });
119 |
120 | it("will properly interpolate optional catch-all routes from the pathname", () => {
121 | memoryRouter.useParser(createDynamicRouteParser(["/one/two/[[...slug]]"]));
122 |
123 | memoryRouter.push("/one/two/three/four");
124 |
125 | expectMatch(memoryRouter, {
126 | pathname: "/one/two/[[...slug]]",
127 | asPath: "/one/two/three/four",
128 | query: { slug: ["three", "four"] },
129 | });
130 | });
131 |
132 | it("will match route with optional catch-all omitted", () => {
133 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]/[[...slug]]"]));
134 |
135 | memoryRouter.push("/entity/42");
136 |
137 | expectMatch(memoryRouter, {
138 | pathname: "/entity/[id]/[[...slug]]",
139 | asPath: "/entity/42",
140 | query: { id: "42" },
141 | });
142 | });
143 |
144 | describe('the "as" parameter', () => {
145 | beforeEach(() => {
146 | memoryRouter.useParser(createDynamicRouteParser(["/path/[testParam]"]));
147 | });
148 | it('uses "as" path param with a dynamic route', async () => {
149 | memoryRouter.push("/path/[testParam]", "/path/456");
150 | expectMatch(memoryRouter, {
151 | asPath: "/path/456",
152 | pathname: "/path/[testParam]",
153 | query: {
154 | testParam: "456",
155 | },
156 | });
157 | });
158 | it('uses "as" path param over "url" path param', async () => {
159 | // This actually doesn't work well in Next, it forces a page refresh
160 | memoryRouter.push("/path/123", "/path/456");
161 | expectMatch(memoryRouter, {
162 | asPath: "/path/456",
163 | pathname: "/path/[testParam]",
164 | query: {
165 | testParam: "456",
166 | },
167 | });
168 | });
169 | it("merges the real query params with the route params", () => {
170 | memoryRouter.push(
171 | {
172 | pathname: "/path/[testParam]",
173 | query: { param: "href" },
174 | },
175 | "/path/456"
176 | );
177 | expectMatch(memoryRouter, {
178 | asPath: "/path/456",
179 | pathname: "/path/[testParam]",
180 | query: {
181 | param: "href",
182 | testParam: "456",
183 | },
184 | });
185 | });
186 | });
187 |
188 | it("hashes are preserved", async () => {
189 | memoryRouter.useParser(createDynamicRouteParser(["/entity/[id]"]));
190 |
191 | memoryRouter.setCurrentUrl("/entity/42#hash");
192 | expectMatch(memoryRouter, {
193 | asPath: "/entity/42#hash",
194 | pathname: "/entity/[id]",
195 | hash: "#hash",
196 | });
197 |
198 | memoryRouter.setCurrentUrl("/entity/42?key=value#hash");
199 | expectMatch(memoryRouter, {
200 | asPath: "/entity/42?key=value#hash",
201 | pathname: "/entity/[id]",
202 | query: { key: "value", id: "42" },
203 | hash: "#hash",
204 | });
205 | });
206 | });
207 |
--------------------------------------------------------------------------------
/src/dynamic-routes/createDynamicRouteParser.tsx:
--------------------------------------------------------------------------------
1 | import type { UrlObjectComplete } from "../MemoryRouter";
2 |
3 | type AbstractedNextDependencies = Pick<
4 | typeof import("next/dist/shared/lib/router/utils") &
5 | typeof import("next/dist/shared/lib/page-path/normalize-page-path") &
6 | typeof import("next/dist/shared/lib/router/utils/route-matcher") &
7 | typeof import("next/dist/shared/lib/router/utils/route-regex"),
8 | "getSortedRoutes" | "getRouteMatcher" | "getRouteRegex" | "isDynamicRoute" | "normalizePagePath"
9 | >;
10 |
11 | /**
12 | * The only differences between Next 10/11/12/13 is the import paths,
13 | * so this "factory" function allows us to abstract these dependencies.
14 | */
15 | export function factory(dependencies: AbstractedNextDependencies) {
16 | checkDependencies(dependencies);
17 | const {
18 | //
19 | getSortedRoutes,
20 | getRouteMatcher,
21 | getRouteRegex,
22 | isDynamicRoute,
23 | normalizePagePath,
24 | } = dependencies;
25 |
26 | return function createDynamicRouteParser(paths: string[]) {
27 | const matchers = getSortedRoutes(paths.map((path) => normalizePagePath(path))).map((path: string) => ({
28 | pathname: path,
29 | match: getRouteMatcher(getRouteRegex(path)),
30 | }));
31 |
32 | return function parser(url: UrlObjectComplete): void {
33 | const pathname = url.pathname;
34 | const isDynamic = isDynamicRoute(pathname);
35 | const matcher = matchers.find((matcher) => matcher.match(pathname));
36 |
37 | if (matcher) {
38 | // Update the route name:
39 | url.pathname = matcher.pathname;
40 |
41 | if (!isDynamic) {
42 | // Extract the route variables from the path:
43 | url.routeParams = matcher.match(pathname) || {};
44 | }
45 | }
46 | };
47 | };
48 | }
49 |
50 | /**
51 | * Check that all these dependencies are properly defined
52 | */
53 | function checkDependencies(dependencies: Record) {
54 | const missingDependencies = Object.keys(dependencies).filter((name) => {
55 | return !dependencies[name];
56 | });
57 | if (missingDependencies.length) {
58 | throw new Error(
59 | `next-router-mock/dynamic-routes: the following dependencies are missing: ${JSON.stringify(missingDependencies)}`
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/dynamic-routes/index.ts:
--------------------------------------------------------------------------------
1 | export declare const createDynamicRouteParser: typeof import("./next-13").createDynamicRouteParser;
2 | // Automatically try to export the correct version:
3 | try {
4 | module.exports = require("./next-13");
5 | } catch (firstErr) {
6 | try {
7 | module.exports = require("./next-12");
8 | } catch {
9 | try {
10 | module.exports = require("./next-11");
11 | } catch {
12 | try {
13 | module.exports = require("./next-10");
14 | } catch {
15 | throw firstErr;
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/dynamic-routes/next-10/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | getRouteMatcher,
3 | getRouteRegex,
4 | getSortedRoutes,
5 | isDynamicRoute,
6 | // @ts-expect-error
7 | } from "next/dist/next-server/lib/router/utils";
8 | // @ts-expect-error
9 | import { normalizePagePath } from "next/dist/next-server/server/normalize-page-path";
10 |
11 | import { factory } from "../createDynamicRouteParser";
12 |
13 | export const createDynamicRouteParser = factory({
14 | getSortedRoutes,
15 | getRouteMatcher,
16 | getRouteRegex,
17 | isDynamicRoute,
18 | normalizePagePath,
19 | });
20 |
--------------------------------------------------------------------------------
/src/dynamic-routes/next-11/index.ts:
--------------------------------------------------------------------------------
1 | import { getRouteMatcher } from "next/dist/shared/lib/router/utils/route-matcher";
2 | import { getRouteRegex } from "next/dist/shared/lib/router/utils/route-regex";
3 | import {
4 | getSortedRoutes,
5 | isDynamicRoute,
6 | //
7 | } from "next/dist/shared/lib/router/utils";
8 | // @ts-expect-error
9 | import { normalizePagePath } from "next/dist/server/normalize-page-path";
10 |
11 | import { factory } from "../createDynamicRouteParser";
12 |
13 | export const createDynamicRouteParser = factory({
14 | getSortedRoutes,
15 | getRouteMatcher,
16 | getRouteRegex,
17 | isDynamicRoute,
18 | normalizePagePath,
19 | });
20 |
--------------------------------------------------------------------------------
/src/dynamic-routes/next-12/index.ts:
--------------------------------------------------------------------------------
1 | import { getRouteMatcher } from "next/dist/shared/lib/router/utils/route-matcher";
2 | import { getRouteRegex } from "next/dist/shared/lib/router/utils/route-regex";
3 | import {
4 | getSortedRoutes,
5 | isDynamicRoute,
6 | //
7 | } from "next/dist/shared/lib/router/utils";
8 | //
9 | import { normalizePagePath } from "next/dist/shared/lib/page-path/normalize-page-path";
10 |
11 | import { factory } from "../createDynamicRouteParser";
12 |
13 | export const createDynamicRouteParser = factory({
14 | getSortedRoutes,
15 | getRouteMatcher,
16 | getRouteRegex,
17 | isDynamicRoute,
18 | normalizePagePath,
19 | });
20 |
--------------------------------------------------------------------------------
/src/dynamic-routes/next-13/index.ts:
--------------------------------------------------------------------------------
1 | // No difference from Next 12:
2 | export * from "../next-12";
3 |
--------------------------------------------------------------------------------
/src/index.test.tsx:
--------------------------------------------------------------------------------
1 | import { useRouterTests } from "./useMemoryRouter.test";
2 |
3 | import router, { MemoryRouter, useRouter, withRouter } from "./index";
4 |
5 | describe("next-overridable-hook", () => {
6 | it("should export a default router", () => {
7 | expect(router).toBeInstanceOf(MemoryRouter);
8 | expect(useRouter).toBeInstanceOf(Function);
9 | expect(withRouter).toBeInstanceOf(Function);
10 | });
11 |
12 | it("the router should have several default properties set", () => {
13 | expect(router).toEqual({
14 | // Ignore these:
15 | events: expect.any(Object),
16 | internal: expect.any(Object),
17 | async: expect.any(Boolean),
18 | push: expect.any(Function),
19 | replace: expect.any(Function),
20 | setCurrentUrl: expect.any(Function),
21 | // Ensure the router has exactly these properties:
22 | asPath: "/",
23 | basePath: "",
24 | hash: "",
25 | isFallback: false,
26 | isLocaleDomain: false,
27 | isPreview: false,
28 | isReady: true,
29 | locale: undefined,
30 | locales: [],
31 | pathname: "/",
32 | query: {},
33 | });
34 | });
35 |
36 | describe("useRouter", () => {
37 | useRouterTests(router, useRouter);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import type { NextComponentType, NextPageContext } from "next";
3 | import type { BaseContext } from "next/dist/shared/lib/utils";
4 | import { MemoryRouter } from "./MemoryRouter";
5 | import { useMemoryRouter } from "./useMemoryRouter";
6 | import { withMemoryRouter, WithRouterProps } from "./withMemoryRouter";
7 | import { MemoryRouterContext } from "./MemoryRouterContext";
8 |
9 | // Export extra mock APIs:
10 | export { useMemoryRouter } from "./useMemoryRouter";
11 | export { MemoryRouter, BaseRouter, Url } from "./MemoryRouter";
12 |
13 | // Export the singleton:
14 | export const memoryRouter = new MemoryRouter();
15 | memoryRouter.async = false;
16 | export default memoryRouter;
17 |
18 | // Export the `useRouter` hook:
19 | export const useRouter = () => {
20 | return (
21 | React.useContext(MemoryRouterContext) || // Allow to override the singleton, if needed
22 | useMemoryRouter(memoryRouter)
23 | );
24 | };
25 |
26 | // Export the `withRouter` HOC:
27 | export const withRouter = (
28 | ComposedComponent: NextComponentType
29 | ) => {
30 | return withMemoryRouter(useRouter, ComposedComponent);
31 | };
32 |
--------------------------------------------------------------------------------
/src/lib/mitt/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | MIT License
3 | Copyright (c) Jason Miller (https://jasonformat.com/)
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7 | */
8 |
9 | // This file is based on https://github.com/developit/mitt/blob/v1.1.3/src/index.js
10 | // It's been edited for the needs of this script
11 | // See the LICENSE at the top of the file
12 |
13 | type Handler = (...evts: any[]) => void;
14 |
15 | export type MittEmitter = {
16 | on(type: T, handler: Handler): void;
17 | off(type: T, handler: Handler): void;
18 | emit(type: T, ...evts: any[]): void;
19 | };
20 |
21 | export default function mitt(): MittEmitter {
22 | const all: { [s: string]: Handler[] } = Object.create(null);
23 |
24 | return {
25 | on(type: string, handler: Handler) {
26 | (all[type] || (all[type] = [])).push(handler);
27 | },
28 |
29 | off(type: string, handler: Handler) {
30 | if (all[type]) {
31 | all[type].splice(all[type].indexOf(handler) >>> 0, 1);
32 | }
33 | },
34 |
35 | emit(type: string, ...evts: any[]) {
36 | // eslint-disable-next-line array-callback-return
37 | (all[type] || []).slice().map((handler: Handler) => {
38 | handler(...evts);
39 | });
40 | },
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/src/navigation/index.test.tsx:
--------------------------------------------------------------------------------
1 | import { act, renderHook, RenderHookResult } from "@testing-library/react";
2 | import singletonRouter from "../index";
3 | import {
4 | useRouter,
5 | useParams,
6 | usePathname,
7 | useSearchParams,
8 | useSelectedLayoutSegment,
9 | useSelectedLayoutSegments,
10 | } from "./index";
11 | import { createDynamicRouteParser } from "../dynamic-routes";
12 |
13 | describe("next/navigation", () => {
14 | beforeEach(() => {
15 | singletonRouter.reset();
16 | });
17 |
18 | describe("useRouter", () => {
19 | const hook = beforeEachRenderHook(() => useRouter());
20 |
21 | it("should be a snapshot of the router", () => {
22 | expect(hook.result.current).not.toBe(singletonRouter);
23 | expect(hook.result.current).toMatchObject({
24 | push: expect.any(Function),
25 | replace: expect.any(Function),
26 | refresh: expect.any(Function),
27 | prefetch: expect.any(Function),
28 | back: expect.any(Function),
29 | forward: expect.any(Function),
30 | });
31 | });
32 | it("returns the same object after rerendering", () => {
33 | const initial = hook.result.current;
34 | hook.rerender();
35 | expect(hook.result.current).toBe(initial);
36 | });
37 | it("pushing a route does not trigger a rerender", () => {
38 | const initial = hook.result.current;
39 | act(() => {
40 | initial.push("/url");
41 | });
42 | expect(hook.result.current).toBe(initial);
43 | });
44 | });
45 |
46 | describe("usePathname", () => {
47 | const hook = beforeEachRenderHook(() => usePathname());
48 | it("should return the current pathname", () => {
49 | expect(hook.result.current).toEqual("/");
50 | });
51 | it("should update when a new path is pushed", () => {
52 | act(() => {
53 | singletonRouter.push("/new-path");
54 | });
55 |
56 | expect(hook.result.current).toEqual("/new-path");
57 | });
58 | });
59 |
60 | describe("useParams", () => {
61 | beforeEach(() => {
62 | singletonRouter.useParser(createDynamicRouteParser(["/[one]/[two]"]));
63 | });
64 | const hook = beforeEachRenderHook(() => useParams());
65 | it("should contain the route params", () => {
66 | expect(hook.result.current).toEqual({});
67 |
68 | act(() => {
69 | singletonRouter.push("/A/B");
70 | });
71 |
72 | expect(hook.result.current).toEqual({ one: "A", two: "B" });
73 | });
74 |
75 | it("should not contain search params", () => {
76 | expect(hook.result.current).toEqual({});
77 |
78 | act(() => {
79 | singletonRouter.push("/A/B?one=ONE&two=TWO&three=THREE");
80 | });
81 |
82 | expect(hook.result.current).toEqual({ one: "A", two: "B" });
83 | });
84 | });
85 |
86 | describe("useSearchParams", () => {
87 | const hook = beforeEachRenderHook(() => useSearchParams());
88 | it("should contain the search params", () => {
89 | expect([...hook.result.current.entries()]).toEqual([]);
90 |
91 | act(() => {
92 | singletonRouter.push("/path?one=1&two=2&three=3");
93 | });
94 |
95 | expect([...hook.result.current.entries()]).toEqual([
96 | ["one", "1"],
97 | ["two", "2"],
98 | ["three", "3"],
99 | ]);
100 | });
101 | });
102 |
103 | describe("useSelectedLayoutSegment", () => {
104 | act(() => {
105 | singletonRouter.push("/segment1/segment2");
106 | });
107 | const hook = beforeEachRenderHook(() => useSelectedLayoutSegment());
108 | it("should show not implemented yet", () => {
109 | expect(hook.result.current).toEqual("[next-router-mock] Not Yet Implemented");
110 | });
111 | });
112 |
113 | describe("useSelectedLayoutSegments", () => {
114 | act(() => {
115 | singletonRouter.push("/segment1/segment2");
116 | });
117 | const hook = beforeEachRenderHook(() => useSelectedLayoutSegments());
118 | it("should show not implemented yet", () => {
119 | expect(hook.result.current).toEqual(["[next-router-mock] Not Yet Implemented"]);
120 | });
121 | });
122 | });
123 |
124 | function beforeEachRenderHook(render: () => T): RenderHookResult {
125 | const hookResult = {} as any;
126 | beforeEach(() => {
127 | const newHookResult = renderHook(render);
128 | Object.assign(hookResult, newHookResult);
129 | });
130 | return hookResult;
131 | }
132 |
--------------------------------------------------------------------------------
/src/navigation/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useMemo } from "react";
2 | import { MemoryRouter } from "../MemoryRouter";
3 | import singletonRouter from "../index";
4 | import type * as NextNav from "next/navigation";
5 |
6 | function useSnapshot(makeSnapshot: (r: MemoryRouter, prev: T | null) => T): T {
7 | const [snapshot, setSnapshot] = useState(() => makeSnapshot(singletonRouter, null));
8 |
9 | useEffect(() => {
10 | // To ensure we don't call setRouter after unmounting:
11 | let isMounted = true;
12 |
13 | const handleRouteChange = () => {
14 | if (!isMounted) return;
15 |
16 | // Ensure the reference changes each render:
17 | setSnapshot((prev) => makeSnapshot(singletonRouter, prev));
18 | };
19 |
20 | singletonRouter.events.on("routeChangeComplete", handleRouteChange);
21 | singletonRouter.events.on("hashChangeComplete", handleRouteChange);
22 | return () => {
23 | isMounted = false;
24 | singletonRouter.events.off("routeChangeComplete", handleRouteChange);
25 | singletonRouter.events.off("hashChangeComplete", handleRouteChange);
26 | };
27 | }, []);
28 |
29 | return snapshot;
30 | }
31 |
32 | export const useRouter: typeof NextNav.useRouter = () => {
33 | // All these methods are static, and never trigger a rerender:
34 | return useMemo(
35 | () => ({
36 | push: (url, options) => singletonRouter.push(url),
37 | replace: (url, options) => singletonRouter.replace(url),
38 | refresh: singletonRouter.reload,
39 | prefetch: singletonRouter.prefetch,
40 | back: singletonRouter.back,
41 | forward: singletonRouter.forward,
42 | }),
43 | []
44 | );
45 | };
46 |
47 | export const useSearchParams: typeof NextNav.useSearchParams = () => {
48 | return useSnapshot((r, prev) => {
49 | const query = r.internal.query;
50 | // Build the search params from the query object:
51 | const newSearchParams = new URLSearchParams();
52 | Object.keys(query).forEach((key) => {
53 | const value = query[key];
54 | if (Array.isArray(value)) {
55 | value.forEach((val) => newSearchParams.append(key, val));
56 | } else if (value !== undefined) {
57 | newSearchParams.append(key, value);
58 | }
59 | });
60 |
61 | // Prevent rerendering if the query is the same:
62 | if (prev && newSearchParams.toString() === prev.toString()) {
63 | return prev;
64 | }
65 | return newSearchParams as NextNav.ReadonlyURLSearchParams;
66 | });
67 | };
68 |
69 | export const usePathname: typeof NextNav.usePathname = () => {
70 | return useSnapshot((r) => r.pathname);
71 | };
72 |
73 | export const useParams: typeof NextNav.useParams = >() => {
74 | return useSnapshot((r) => r.internal.routeParams as T);
75 | };
76 |
77 | export const useSelectedLayoutSegment: typeof NextNav.useSelectedLayoutSegment = () =>
78 | useSnapshot((r) => r.internal.selectedLayoutSegment);
79 | export const useSelectedLayoutSegments: typeof NextNav.useSelectedLayoutSegments = () =>
80 | useSnapshot((r) => r.internal.selectedLayoutSegments);
81 |
--------------------------------------------------------------------------------
/src/next-link.test.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import NextLink from "next/link";
3 | import { fireEvent, render, screen, waitFor } from "@testing-library/react";
4 |
5 | import memoryRouter from "./index";
6 | import { MemoryRouterProvider } from "./MemoryRouterProvider";
7 |
8 | jest.mock("next/dist/client/router", () => require("./index"));
9 |
10 | const wrapper = (props: { children: React.ReactNode }) => ;
11 |
12 | describe("next/link", () => {
13 | describe("clicking a link will mock navigate", () => {
14 | it("to a href", async () => {
15 | render(Example Link, { wrapper });
16 | fireEvent.click(screen.getByText("Example Link"));
17 | await waitFor(() => {
18 | expect(memoryRouter).toMatchObject({
19 | asPath: "/example?foo=bar",
20 | pathname: "/example",
21 | query: { foo: "bar" },
22 | });
23 | });
24 | });
25 |
26 | it("to a URL object", async () => {
27 | render(Example Link, { wrapper });
28 | fireEvent.click(screen.getByText("Example Link"));
29 | await waitFor(() => {
30 | expect(memoryRouter).toMatchObject({
31 | asPath: "/example?foo=bar",
32 | pathname: "/example",
33 | query: { foo: "bar" },
34 | });
35 | });
36 | });
37 |
38 | it("supports multivalued query properties", async () => {
39 | render(Next Link, {
40 | wrapper,
41 | });
42 | fireEvent.click(screen.getByText("Next Link"));
43 | await waitFor(() => {
44 | expect(memoryRouter).toMatchObject({
45 | asPath: "/example?foo=bar&foo=baz",
46 | pathname: "/example",
47 | query: { foo: ["bar", "baz"] },
48 | });
49 | });
50 | });
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/src/urls.ts:
--------------------------------------------------------------------------------
1 | import type { NextRouter } from "next/router";
2 | import type { UrlObject } from "./MemoryRouter";
3 |
4 | export function parseUrl(url: string): UrlObject {
5 | const base = "https://base.com"; // base can be anything
6 | const parsed = new URL(url, base);
7 | const query = Object.fromEntries(
8 | Array.from(parsed.searchParams.keys()).map((key) => {
9 | const values = parsed.searchParams.getAll(key);
10 | return [key, values.length === 1 ? values[0] : values];
11 | })
12 | );
13 | return {
14 | pathname: parsed.pathname,
15 | hash: parsed.hash,
16 | query,
17 | };
18 | }
19 | export function stringifyQueryString(query: NextRouter["query"]): string {
20 | const params = new URLSearchParams();
21 | Object.keys(query).forEach((key) => {
22 | const values = query[key];
23 | for (const value of Array.isArray(values) ? values : [values]) {
24 | params.append(key, value!);
25 | }
26 | });
27 | return params.toString();
28 | }
29 | export function parseQueryString(query: string): NextRouter["query"] | undefined {
30 | const parsedUrl = parseUrl(`?${query}`);
31 |
32 | return parsedUrl.query;
33 | }
34 |
--------------------------------------------------------------------------------
/src/useMemoryRouter.test.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from "react";
2 | import { act, renderHook } from "@testing-library/react";
3 |
4 | import { MemoryRouter, MemoryRouterSnapshot } from "./MemoryRouter";
5 | import { useMemoryRouter } from "./useMemoryRouter";
6 |
7 | export function useRouterTests(singletonRouter: MemoryRouter, useRouter: () => MemoryRouterSnapshot) {
8 | it("the useRouter hook only returns a snapshot of the singleton router", async () => {
9 | const { result } = renderHook(() => useRouter());
10 |
11 | expect(result.current).not.toBe(singletonRouter);
12 | });
13 |
14 | it("will allow capturing previous route values in hooks with routing events", async () => {
15 | // see: https://github.com/streamich/react-use/blob/master/src/usePrevious.ts
16 | const usePrevious = function (value: T): T | undefined {
17 | const previous = useRef();
18 |
19 | useEffect(() => {
20 | previous.current = value;
21 | });
22 |
23 | return previous.current;
24 | };
25 |
26 | const useRouterWithPrevious = () => {
27 | const { asPath } = useRouter();
28 | const previousAsPath = usePrevious(asPath);
29 |
30 | return [previousAsPath, asPath];
31 | };
32 |
33 | // Set initial state:
34 | singletonRouter.setCurrentUrl("/foo");
35 |
36 | const { result } = renderHook(() => useRouterWithPrevious());
37 |
38 | expect(result.current).toEqual([undefined, "/foo"]);
39 |
40 | await act(async () => {
41 | await singletonRouter.push("/foo?bar=baz");
42 | });
43 |
44 | expect(result.current).toEqual(["/foo", "/foo?bar=baz"]);
45 | });
46 |
47 | it('"push" will cause a rerender with the new route', async () => {
48 | const { result } = renderHook(() => useRouter());
49 |
50 | await act(async () => {
51 | await result.current.push("/foo?bar=baz");
52 | });
53 |
54 | expect(result.current).not.toBe(singletonRouter);
55 | expect(result.current).toEqual(singletonRouter);
56 | expect(result.current).toMatchObject({
57 | asPath: "/foo?bar=baz",
58 | pathname: "/foo",
59 | query: { bar: "baz" },
60 | });
61 | });
62 |
63 | it('changing just the "hash" will cause a rerender', async () => {
64 | const { result } = renderHook(() => useRouter());
65 |
66 | await act(async () => {
67 | await result.current.push("/foo");
68 | await result.current.push("/foo#bar");
69 | });
70 | const expected = {
71 | asPath: "/foo#bar",
72 | pathname: "/foo",
73 | hash: "#bar",
74 | };
75 | expect(singletonRouter).toMatchObject(expected);
76 | expect(result.current).toMatchObject(expected);
77 | });
78 |
79 | it('calling "push" multiple times will rerender with the correct route', async () => {
80 | const { result } = renderHook(() => useRouter());
81 |
82 | // Push using the router instance:
83 | await act(async () => {
84 | result.current.push("/one");
85 | result.current.push("/two");
86 | await result.current.push("/three");
87 | });
88 |
89 | expect(result.current).toMatchObject({
90 | asPath: "/three",
91 | });
92 |
93 | // Push using the singleton router:
94 | await act(async () => {
95 | singletonRouter.push("/four");
96 | singletonRouter.push("/five");
97 | await singletonRouter.push("/six");
98 | });
99 | expect(result.current).toMatchObject({
100 | asPath: "/six",
101 | });
102 |
103 | // Push using the router instance (again):
104 | await act(async () => {
105 | result.current.push("/seven");
106 | result.current.push("/eight");
107 | await result.current.push("/nine");
108 | });
109 |
110 | expect(result.current).toMatchObject({
111 | asPath: "/nine",
112 | });
113 | });
114 |
115 | it("the singleton and the router instances can be used interchangeably", async () => {
116 | const { result } = renderHook(() => useRouter());
117 | await act(async () => {
118 | await result.current.push("/one");
119 | });
120 | expect(result.current).toMatchObject({ asPath: "/one" });
121 | expect(result.current).toMatchObject(singletonRouter);
122 |
123 | await act(async () => {
124 | await result.current.push("/two");
125 | });
126 | expect(result.current).toMatchObject({ asPath: "/two" });
127 | expect(result.current).toMatchObject(singletonRouter);
128 |
129 | await act(async () => {
130 | await singletonRouter.push("/three");
131 | });
132 | expect(result.current).toMatchObject({ asPath: "/three" });
133 | expect(result.current).toMatchObject(singletonRouter);
134 | });
135 |
136 | it("support the locales and locale properties", async () => {
137 | const { result } = renderHook(() => useRouter());
138 | expect(result.current.locale).toBe(undefined);
139 | expect(result.current.locales).toEqual([]);
140 |
141 | await act(async () => {
142 | await result.current.push("/", undefined, { locale: "en" });
143 | });
144 | expect(result.current.locale).toBe("en");
145 | });
146 | }
147 |
148 | describe("useMemoryRouter", () => {
149 | const singletonRouter = new MemoryRouter();
150 | const useRouter = () => useMemoryRouter(singletonRouter);
151 | useRouterTests(singletonRouter, useRouter);
152 | });
153 |
--------------------------------------------------------------------------------
/src/useMemoryRouter.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | import { MemoryRouter } from "./MemoryRouter";
4 |
5 | export type MemoryRouterEventHandlers = {
6 | onHashChangeStart?: (url: string, options: { shallow: boolean }) => void;
7 | onHashChangeComplete?: (url: string, options: { shallow: boolean }) => void;
8 | onRouteChangeStart?: (url: string, options: { shallow: boolean }) => void;
9 | onRouteChangeComplete?: (url: string, options: { shallow: boolean }) => void;
10 | onPush?: (url: string, options: { shallow: boolean }) => void;
11 | onReplace?: (url: string, options: { shallow: boolean }) => void;
12 | };
13 |
14 | export const useMemoryRouter = (singletonRouter: MemoryRouter, eventHandlers?: MemoryRouterEventHandlers) => {
15 | const [router, setRouter] = useState(() => MemoryRouter.snapshot(singletonRouter));
16 |
17 | // Trigger updates on route changes:
18 | useEffect(() => {
19 | // To ensure we don't call setRouter after unmounting:
20 | let isMounted = true;
21 |
22 | const handleRouteChange = () => {
23 | if (!isMounted) return;
24 |
25 | // Ensure the reference changes each render:
26 | setRouter(MemoryRouter.snapshot(singletonRouter));
27 | };
28 |
29 | singletonRouter.events.on("routeChangeComplete", handleRouteChange);
30 | singletonRouter.events.on("hashChangeComplete", handleRouteChange);
31 | return () => {
32 | isMounted = false;
33 | singletonRouter.events.off("routeChangeComplete", handleRouteChange);
34 | singletonRouter.events.off("hashChangeComplete", handleRouteChange);
35 | };
36 | }, [singletonRouter]);
37 |
38 | // Subscribe to any eventHandlers:
39 | useEffect(() => {
40 | if (!eventHandlers) return;
41 | const {
42 | //
43 | onRouteChangeStart,
44 | onRouteChangeComplete,
45 | onHashChangeStart,
46 | onHashChangeComplete,
47 | onPush,
48 | onReplace,
49 | } = eventHandlers;
50 | if (onRouteChangeStart) singletonRouter.events.on("routeChangeStart", onRouteChangeStart);
51 | if (onRouteChangeComplete) singletonRouter.events.on("routeChangeComplete", onRouteChangeComplete);
52 | if (onHashChangeStart) singletonRouter.events.on("hashChangeStart", onHashChangeStart);
53 | if (onHashChangeComplete) singletonRouter.events.on("hashChangeComplete", onHashChangeComplete);
54 | if (onPush) singletonRouter.events.on("NEXT_ROUTER_MOCK:push", onPush);
55 | if (onReplace) singletonRouter.events.on("NEXT_ROUTER_MOCK:replace", onReplace);
56 | return () => {
57 | if (onRouteChangeStart) singletonRouter.events.off("routeChangeStart", onRouteChangeStart);
58 | if (onRouteChangeComplete) singletonRouter.events.off("routeChangeComplete", onRouteChangeComplete);
59 | if (onHashChangeStart) singletonRouter.events.off("hashChangeStart", onHashChangeStart);
60 | if (onHashChangeComplete) singletonRouter.events.off("hashChangeComplete", onHashChangeComplete);
61 | if (onPush) singletonRouter.events.off("NEXT_ROUTER_MOCK:push", onPush);
62 | if (onReplace) singletonRouter.events.off("NEXT_ROUTER_MOCK:replace", onReplace);
63 | };
64 | }, [
65 | singletonRouter.events,
66 | eventHandlers?.onRouteChangeStart,
67 | eventHandlers?.onRouteChangeComplete,
68 | eventHandlers?.onHashChangeStart,
69 | eventHandlers?.onHashChangeComplete,
70 | eventHandlers?.onPush,
71 | eventHandlers?.onReplace,
72 | ]);
73 |
74 | return router;
75 | };
76 |
--------------------------------------------------------------------------------
/src/withMemoryRouter.test.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { NextRouter } from "next/router";
3 | import { act, render, screen } from "@testing-library/react";
4 | import { memoryRouter, withRouter } from "./index";
5 |
6 | class TestComponent extends Component<{ router: NextRouter; title?: string }, {}> {
7 | render() {
8 | return (
9 |
10 | {this.props.title || "Current path"}: "{this.props.router.asPath}"
11 |
12 | );
13 | }
14 |
15 | static getInitialProps() {}
16 | }
17 |
18 | const TestComponentWrapper = withRouter(TestComponent);
19 |
20 | describe("withRouter", () => {
21 | beforeEach(() => {
22 | memoryRouter.setCurrentUrl("/test");
23 | });
24 |
25 | it("should have access to the current router", async () => {
26 | render();
27 | expect(screen.getByText('Current path: "/test"')).toBeDefined();
28 | });
29 |
30 | it("should respond to updates", () => {
31 | render();
32 | act(() => {
33 | memoryRouter.push("/updated-path");
34 | });
35 | expect(screen.getByText('Current path: "/updated-path"')).toBeDefined();
36 | });
37 |
38 | it("should pass-through extra properties", () => {
39 | render();
40 | expect(screen.getByText('CURRENT PATH: "/test"')).toBeDefined();
41 | });
42 |
43 | it("should copy the static `getInitialProps` method", () => {
44 | expect(TestComponentWrapper.getInitialProps).toBe(TestComponent.getInitialProps);
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/src/withMemoryRouter.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import type { NextComponentType, NextPageContext } from "next";
3 | import type { BaseContext } from "next/dist/shared/lib/utils";
4 | import type { NextRouter } from "next/router";
5 |
6 | // This is a (very slightly) modified version of https://github.com/vercel/next.js/blob/canary/packages/next/client/with-router.tsx
7 |
8 | import type { MemoryRouterSnapshot } from "./MemoryRouter";
9 |
10 | export type WithRouterProps = {
11 | router: NextRouter;
12 | };
13 |
14 | export type ExcludeRouterProps = Pick
>;
15 |
16 | export function withMemoryRouter
(
17 | useRouter: () => MemoryRouterSnapshot,
18 | ComposedComponent: NextComponentType
19 | ): NextComponentType> {
20 | function WithRouterWrapper(props: any): JSX.Element {
21 | return ;
22 | }
23 |
24 | WithRouterWrapper.getInitialProps = ComposedComponent.getInitialProps;
25 | // This is needed to allow checking for custom getInitialProps in _app
26 | WithRouterWrapper.origGetInitialProps = (ComposedComponent as any).origGetInitialProps;
27 | if (process.env.NODE_ENV !== "production") {
28 | const name = ComposedComponent.displayName || ComposedComponent.name || "Unknown";
29 | WithRouterWrapper.displayName = `withRouter(${name})`;
30 | }
31 |
32 | return WithRouterWrapper;
33 | }
34 |
--------------------------------------------------------------------------------
/test/example-app/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/test/example-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/test/example-app/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/test/example-app/components/Search.stories.tsx:
--------------------------------------------------------------------------------
1 | import { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider/next-13";
2 | import { Search } from "./Search";
3 |
4 | const MemoryRouterDecorator = (Story: React.ComponentType) => (
5 |
6 |
7 |
8 | );
9 |
10 | export default {
11 | title: "components / Search",
12 | component: Search,
13 | decorators: [MemoryRouterDecorator],
14 | };
15 |
--------------------------------------------------------------------------------
/test/example-app/components/Search.test.tsx:
--------------------------------------------------------------------------------
1 | import { Search } from "./Search";
2 |
3 | jest.mock("next/router", () => jest.requireActual("next-router-mock"));
4 |
5 | describe("Search", () => {
6 | it("TODO add tests", () => {
7 | expect(typeof Search).toBe("function");
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/test/example-app/components/Search.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useRouter } from "next/router";
3 |
4 | /**
5 | * A Search input that keeps the `search` parameter in the current URL
6 | */
7 | export const Search = () => {
8 | const router = useRouter();
9 |
10 | const value = router.query.search || "";
11 |
12 | const onChange = (ev: React.ChangeEvent) => {
13 | const newSearch = ev.currentTarget.value;
14 | router.replace({
15 | query: {
16 | ...router.query,
17 | search: newSearch,
18 | },
19 | });
20 | };
21 |
22 | return ;
23 | };
24 |
--------------------------------------------------------------------------------
/test/example-app/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | swcMinify: true,
5 | }
6 |
7 | module.exports = nextConfig
8 |
--------------------------------------------------------------------------------
/test/example-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "checks": "npm run test && npm run typecheck",
7 | "test": "echo TODO add tests",
8 | "typecheck": "tsc --noEmit",
9 | "dev": "next dev"
10 | },
11 | "dependencies": {
12 | "next": "^13.1.2",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@babel/core": "^7.20.12",
18 | "@storybook/addon-actions": "^6.5.15",
19 | "@types/node": "^18.11.9",
20 | "@types/react": "^18.0.26",
21 | "@types/react-dom": "^18.0.10",
22 | "babel-loader": "^8.3.0",
23 | "typescript": "^4.9.4"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/example-app/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css'
2 | import type { AppProps } from 'next/app'
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/test/example-app/pages/as-tests/[[...route]].tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, PropsWithChildren, ReactEventHandler, useState } from "react";
2 | import NextLink, { LinkProps as NextLinkProps } from "next/link";
3 | import { Router, useRouter } from "next/router";
4 |
5 | const root = "/as-tests";
6 |
7 | const Page = () => {
8 | const [activeId, setActiveId] = useState(-1);
9 | const [expectedValues, setExpectedValues] = useState>({
10 | asPath: "",
11 | pathname: "",
12 | query: {},
13 | });
14 |
15 | let index = 0;
16 | const expected = (expectedDetails: typeof expectedValues) => {
17 | const id = index++;
18 | return {
19 | onClick: () => {
20 | setActiveId(id);
21 | setExpectedValues(expectedDetails);
22 | },
23 | active: id === activeId,
24 | };
25 | };
26 |
27 | const router = useRouter();
28 | const values = {
29 | "root path": root,
30 | "router.asPath": router.asPath.replace(root, ""),
31 | "expect.asPath": expectedValues.asPath,
32 | "router.pathname": router.pathname.replace(root, ""),
33 | "expect.pathname": expectedValues.pathname,
34 | "router.query": router.query,
35 | "expect.query": expectedValues.query,
36 | };
37 | const pathname = "/[[...route]]";
38 |
39 | return (
40 | <>
41 |
88 |
89 |
136 |
137 |
172 |
173 |
197 |
198 |
202 | >
203 | );
204 | };
205 | const TestLink: FC<
206 | Pick & {
207 | label: string;
208 | active: boolean;
209 | onClick: ReactEventHandler;
210 | }
211 | > = ({ label, href, as, active, onClick }) => {
212 | const normalizeUrl = (url: typeof as) => {
213 | // Prepend the 'root' URL:
214 | if (typeof url === "string") {
215 | return root + url;
216 | }
217 | if (typeof url === "object") {
218 | url = { ...url, pathname: root + (url.pathname || "") };
219 | }
220 | return url;
221 | };
222 | return (
223 |
231 | {label}
232 | (href {JSON.stringify(href)}
as {JSON.stringify(as)}
)
233 |
234 | );
235 | };
236 |
237 | const DetailsTable: FC<{ values: object }> = ({ values }) => {
238 | return (
239 |
240 | {Object.keys(values).map((key) => {
241 | const value = values[key as keyof typeof values];
242 | return (
243 |
244 | {JSON.stringify(value)}
245 |
246 | );
247 | })}
248 |
249 | );
250 | };
251 |
252 | const Table: FC> = ({ children }) => {
253 | return (
254 |
257 | );
258 | };
259 |
260 | const Row: FC<
261 | PropsWithChildren<{
262 | label: string;
263 | }>
264 | > = ({ label = "", children }) => {
265 | return (
266 |
267 |
268 | {label}
269 | |
270 | {children} |
271 |
272 | );
273 | };
274 |
275 | export default Page;
276 |
--------------------------------------------------------------------------------
/test/example-app/pages/as-tests/as-path.tsx:
--------------------------------------------------------------------------------
1 | export { default } from "./[[...route]]";
2 |
--------------------------------------------------------------------------------
/test/example-app/pages/as-tests/real-path.tsx:
--------------------------------------------------------------------------------
1 | export { default } from "./[[...route]]";
2 |
--------------------------------------------------------------------------------
/test/example-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scottrippey/next-router-mock/aa891b21af1168e32bb6eb5a4279e86ccf1dcca9/test/example-app/public/favicon.ico
--------------------------------------------------------------------------------
/test/example-app/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/test/example-app/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: 0 2rem;
3 | }
4 |
5 | .main {
6 | min-height: 100vh;
7 | padding: 4rem 0;
8 | flex: 1;
9 | display: flex;
10 | flex-direction: column;
11 | justify-content: center;
12 | align-items: center;
13 | }
14 |
15 | .footer {
16 | display: flex;
17 | flex: 1;
18 | padding: 2rem 0;
19 | border-top: 1px solid #eaeaea;
20 | justify-content: center;
21 | align-items: center;
22 | }
23 |
24 | .footer a {
25 | display: flex;
26 | justify-content: center;
27 | align-items: center;
28 | flex-grow: 1;
29 | }
30 |
31 | .title a {
32 | color: #0070f3;
33 | text-decoration: none;
34 | }
35 |
36 | .title a:hover,
37 | .title a:focus,
38 | .title a:active {
39 | text-decoration: underline;
40 | }
41 |
42 | .title {
43 | margin: 0;
44 | line-height: 1.15;
45 | font-size: 4rem;
46 | }
47 |
48 | .title,
49 | .description {
50 | text-align: center;
51 | }
52 |
53 | .description {
54 | margin: 4rem 0;
55 | line-height: 1.5;
56 | font-size: 1.5rem;
57 | }
58 |
59 | .code {
60 | background: #fafafa;
61 | border-radius: 5px;
62 | padding: 0.75rem;
63 | font-size: 1.1rem;
64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
65 | Bitstream Vera Sans Mono, Courier New, monospace;
66 | }
67 |
68 | .grid {
69 | display: flex;
70 | align-items: center;
71 | justify-content: center;
72 | flex-wrap: wrap;
73 | max-width: 800px;
74 | }
75 |
76 | .card {
77 | margin: 1rem;
78 | padding: 1.5rem;
79 | text-align: left;
80 | color: inherit;
81 | text-decoration: none;
82 | border: 1px solid #eaeaea;
83 | border-radius: 10px;
84 | transition: color 0.15s ease, border-color 0.15s ease;
85 | max-width: 300px;
86 | }
87 |
88 | .card:hover,
89 | .card:focus,
90 | .card:active {
91 | color: #0070f3;
92 | border-color: #0070f3;
93 | }
94 |
95 | .card h2 {
96 | margin: 0 0 1rem 0;
97 | font-size: 1.5rem;
98 | }
99 |
100 | .card p {
101 | margin: 0;
102 | font-size: 1.25rem;
103 | line-height: 1.5;
104 | }
105 |
106 | .logo {
107 | height: 1em;
108 | margin-left: 0.5rem;
109 | }
110 |
111 | @media (max-width: 600px) {
112 | .grid {
113 | width: 100%;
114 | flex-direction: column;
115 | }
116 | }
117 |
118 | @media (prefers-color-scheme: dark) {
119 | .card,
120 | .footer {
121 | border-color: #222;
122 | }
123 | .code {
124 | background: #111;
125 | }
126 | .logo img {
127 | filter: invert(1);
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/test/example-app/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | * {
10 | box-sizing: border-box;
11 | }
12 |
13 | @media (prefers-color-scheme: dark) {
14 | html {
15 | color-scheme: dark;
16 | }
17 | body {
18 | color: white;
19 | background: black;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/example-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "paths": {
18 | "next-router-mock": ["../.."],
19 | "next-router-mock/*": ["../../*"]
20 | }
21 | },
22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
23 | "exclude": ["node_modules"]
24 | }
25 |
--------------------------------------------------------------------------------
/test/next-10/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-10/next-10.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-10";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-10";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-10", () => {
15 | require("next-router-mock/dynamic-routes/next-10");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-10", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-10");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-10/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "10.2.3",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/next-11/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-11/next-11.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-11";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-11";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-11", () => {
15 | require("next-router-mock/dynamic-routes/next-11");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-11", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-11");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-11/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "11.1.4",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/next-12.2+/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-12.2+/next-12.2.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-12";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-12";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-12", () => {
15 | require("next-router-mock/dynamic-routes/next-12");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-12", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-12");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-12.2+/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-12.2+",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "next": "12.3.2",
9 | "next-router-mock": "../.."
10 | }
11 | },
12 | "../..": {
13 | "version": "1.0.0",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "@changesets/cli": "^2.26.2",
17 | "@testing-library/react": "^13.4.0",
18 | "@types/jest": "^26.0.20",
19 | "doctoc": "^2.2.0",
20 | "jest": "^26.6.3",
21 | "next": "^13.5.1",
22 | "prettier": "^2.2.1",
23 | "react": "^18.2.0",
24 | "react-dom": "^18.2.0",
25 | "react-test-renderer": "^18.2.0",
26 | "rimraf": "^3.0.2",
27 | "ts-jest": "^26.4.4",
28 | "typescript": "^4.9.5"
29 | },
30 | "peerDependencies": {
31 | "next": ">=10.0.0",
32 | "react": ">=17.0.0"
33 | }
34 | },
35 | "node_modules/@next/env": {
36 | "version": "12.3.2",
37 | "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.2.tgz",
38 | "integrity": "sha512-upwtMaHxlv/udAWGq0kE+rg8huwmcxQPsKZFhS1R5iVO323mvxEBe1YrSXe1awLbg9sTIuEHbgxjLLt7JbeuAQ=="
39 | },
40 | "node_modules/@next/swc-android-arm-eabi": {
41 | "version": "12.3.2",
42 | "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.2.tgz",
43 | "integrity": "sha512-r2rrz+DZ8YYGqzVrbRrpP6GKzwozpOrnFbErc4k36vUTSFMag9yQahZfaBe06JYdqu/e5yhm/saIDEaSVPRP4g==",
44 | "cpu": [
45 | "arm"
46 | ],
47 | "optional": true,
48 | "os": [
49 | "android"
50 | ],
51 | "engines": {
52 | "node": ">= 10"
53 | }
54 | },
55 | "node_modules/@next/swc-android-arm64": {
56 | "version": "12.3.2",
57 | "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.2.tgz",
58 | "integrity": "sha512-B+TINJhCf+CrY1+b3/JWQlkecv53rAGa/gA7gi5B1cnBa/2Uvoe+Ue0JeCefTjfiyl1ScsyNx+NcESY8Ye2Ngg==",
59 | "cpu": [
60 | "arm64"
61 | ],
62 | "optional": true,
63 | "os": [
64 | "android"
65 | ],
66 | "engines": {
67 | "node": ">= 10"
68 | }
69 | },
70 | "node_modules/@next/swc-darwin-arm64": {
71 | "version": "12.3.2",
72 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.2.tgz",
73 | "integrity": "sha512-PTUfe1ZrwjsiuTmr3bOM9lsoy5DCmfYsLOUF9ZVhtbi5MNJVmUTy4VZ06GfrvnCO5hGCr48z3vpFE9QZ0qLcPw==",
74 | "cpu": [
75 | "arm64"
76 | ],
77 | "optional": true,
78 | "os": [
79 | "darwin"
80 | ],
81 | "engines": {
82 | "node": ">= 10"
83 | }
84 | },
85 | "node_modules/@next/swc-darwin-x64": {
86 | "version": "12.3.2",
87 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.2.tgz",
88 | "integrity": "sha512-1HkjmS9awwlaeEY8Y01nRSNkSv3y+qnC/mjMPe/W66hEh3QKa/LQHqHeS7NOdEs19B2mhZ7w+EgMRXdLQ0Su8w==",
89 | "cpu": [
90 | "x64"
91 | ],
92 | "optional": true,
93 | "os": [
94 | "darwin"
95 | ],
96 | "engines": {
97 | "node": ">= 10"
98 | }
99 | },
100 | "node_modules/@next/swc-freebsd-x64": {
101 | "version": "12.3.2",
102 | "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.2.tgz",
103 | "integrity": "sha512-h5Mx0BKDCJ5Vu/U8e07esF6PjPv1EJgmRbYWTUZMAflu13MQpCJkKEJir7+BeRfTXRfgFf+llc7uocrpd7mcrg==",
104 | "cpu": [
105 | "x64"
106 | ],
107 | "optional": true,
108 | "os": [
109 | "freebsd"
110 | ],
111 | "engines": {
112 | "node": ">= 10"
113 | }
114 | },
115 | "node_modules/@next/swc-linux-arm-gnueabihf": {
116 | "version": "12.3.2",
117 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.2.tgz",
118 | "integrity": "sha512-EuRZAamoxfe/WoWRaC0zsCAoE4gs/mEhilcloNM4J5Mnb3PLY8PZV394W7t5tjBjItMCF7l2Ebwjwtm46tq2RA==",
119 | "cpu": [
120 | "arm"
121 | ],
122 | "optional": true,
123 | "os": [
124 | "linux"
125 | ],
126 | "engines": {
127 | "node": ">= 10"
128 | }
129 | },
130 | "node_modules/@next/swc-linux-arm64-gnu": {
131 | "version": "12.3.2",
132 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.2.tgz",
133 | "integrity": "sha512-T9GCFyOIb4S3acA9LqflUYD+QZ94iZketHCqKdoO0Nx0OCHIgGJV5rotDe8TDXwh/goYpIfyHU4j1qqw4w4VnA==",
134 | "cpu": [
135 | "arm64"
136 | ],
137 | "optional": true,
138 | "os": [
139 | "linux"
140 | ],
141 | "engines": {
142 | "node": ">= 10"
143 | }
144 | },
145 | "node_modules/@next/swc-linux-arm64-musl": {
146 | "version": "12.3.2",
147 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.2.tgz",
148 | "integrity": "sha512-hxNVZS6L3c2z3l9EH2GP0MGQ9exu6O8cohYNZyqC9WUl6C03sEn8xzDH1y+NgD3fVurvYkGU5F0PDddJJLfDIw==",
149 | "cpu": [
150 | "arm64"
151 | ],
152 | "optional": true,
153 | "os": [
154 | "linux"
155 | ],
156 | "engines": {
157 | "node": ">= 10"
158 | }
159 | },
160 | "node_modules/@next/swc-linux-x64-gnu": {
161 | "version": "12.3.2",
162 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.2.tgz",
163 | "integrity": "sha512-fCPkLuwDwY8/QeXxciJJjDHG09liZym/Bhb4A+RLFQ877wUkwFsNWDUTSdUx0YXlYK/1gf67BKauqKkOKp6CYw==",
164 | "cpu": [
165 | "x64"
166 | ],
167 | "optional": true,
168 | "os": [
169 | "linux"
170 | ],
171 | "engines": {
172 | "node": ">= 10"
173 | }
174 | },
175 | "node_modules/@next/swc-linux-x64-musl": {
176 | "version": "12.3.2",
177 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.2.tgz",
178 | "integrity": "sha512-o+GifBIQ2K+/MEFxHsxUZoU3bsuVFLXZYWd3idimFHiVdDCVYiKsY6mYMmKDlucX+9xRyOCkKL9Tjf+3tuXJpw==",
179 | "cpu": [
180 | "x64"
181 | ],
182 | "optional": true,
183 | "os": [
184 | "linux"
185 | ],
186 | "engines": {
187 | "node": ">= 10"
188 | }
189 | },
190 | "node_modules/@next/swc-win32-arm64-msvc": {
191 | "version": "12.3.2",
192 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.2.tgz",
193 | "integrity": "sha512-crii66irzGGMSUR0L8r9+A06eTv7FTXqw4rgzJ33M79EwQJOdpY7RVKXLQMurUhniEeQEEOfamiEdPIi/qxisw==",
194 | "cpu": [
195 | "arm64"
196 | ],
197 | "optional": true,
198 | "os": [
199 | "win32"
200 | ],
201 | "engines": {
202 | "node": ">= 10"
203 | }
204 | },
205 | "node_modules/@next/swc-win32-ia32-msvc": {
206 | "version": "12.3.2",
207 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.2.tgz",
208 | "integrity": "sha512-5hRUSvn3MdQ4nVRu1rmKxq5YJzpTtZfaC/NyGw6wa4NSF1noUn/pdQGUr+I5Qz3CZkd1gZzzC0eaXQHlrk0E2g==",
209 | "cpu": [
210 | "ia32"
211 | ],
212 | "optional": true,
213 | "os": [
214 | "win32"
215 | ],
216 | "engines": {
217 | "node": ">= 10"
218 | }
219 | },
220 | "node_modules/@next/swc-win32-x64-msvc": {
221 | "version": "12.3.2",
222 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.2.tgz",
223 | "integrity": "sha512-tpQJYUH+TzPMIsdVl9fH8uDg47iwiNjKY+8e9da3dXqlkztKzjSw0OwSADoqh3KrifplXeKSta+BBGLdBqg3sg==",
224 | "cpu": [
225 | "x64"
226 | ],
227 | "optional": true,
228 | "os": [
229 | "win32"
230 | ],
231 | "engines": {
232 | "node": ">= 10"
233 | }
234 | },
235 | "node_modules/@swc/helpers": {
236 | "version": "0.4.11",
237 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
238 | "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==",
239 | "dependencies": {
240 | "tslib": "^2.4.0"
241 | }
242 | },
243 | "node_modules/caniuse-lite": {
244 | "version": "1.0.30001431",
245 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
246 | "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==",
247 | "funding": [
248 | {
249 | "type": "opencollective",
250 | "url": "https://opencollective.com/browserslist"
251 | },
252 | {
253 | "type": "tidelift",
254 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
255 | }
256 | ]
257 | },
258 | "node_modules/js-tokens": {
259 | "version": "4.0.0",
260 | "license": "MIT",
261 | "peer": true
262 | },
263 | "node_modules/loose-envify": {
264 | "version": "1.4.0",
265 | "license": "MIT",
266 | "peer": true,
267 | "dependencies": {
268 | "js-tokens": "^3.0.0 || ^4.0.0"
269 | },
270 | "bin": {
271 | "loose-envify": "cli.js"
272 | }
273 | },
274 | "node_modules/nanoid": {
275 | "version": "3.3.4",
276 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
277 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
278 | "bin": {
279 | "nanoid": "bin/nanoid.cjs"
280 | },
281 | "engines": {
282 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
283 | }
284 | },
285 | "node_modules/next": {
286 | "version": "12.3.2",
287 | "resolved": "https://registry.npmjs.org/next/-/next-12.3.2.tgz",
288 | "integrity": "sha512-orzvvebCwOqaz1eA5ZA0R5dbKxqtJyw7yeig7kDspu6p8OrplfyelzpvMHcDTKscv/l0nn/0l0v3mSsE8w4k7A==",
289 | "dependencies": {
290 | "@next/env": "12.3.2",
291 | "@swc/helpers": "0.4.11",
292 | "caniuse-lite": "^1.0.30001406",
293 | "postcss": "8.4.14",
294 | "styled-jsx": "5.0.7",
295 | "use-sync-external-store": "1.2.0"
296 | },
297 | "bin": {
298 | "next": "dist/bin/next"
299 | },
300 | "engines": {
301 | "node": ">=12.22.0"
302 | },
303 | "optionalDependencies": {
304 | "@next/swc-android-arm-eabi": "12.3.2",
305 | "@next/swc-android-arm64": "12.3.2",
306 | "@next/swc-darwin-arm64": "12.3.2",
307 | "@next/swc-darwin-x64": "12.3.2",
308 | "@next/swc-freebsd-x64": "12.3.2",
309 | "@next/swc-linux-arm-gnueabihf": "12.3.2",
310 | "@next/swc-linux-arm64-gnu": "12.3.2",
311 | "@next/swc-linux-arm64-musl": "12.3.2",
312 | "@next/swc-linux-x64-gnu": "12.3.2",
313 | "@next/swc-linux-x64-musl": "12.3.2",
314 | "@next/swc-win32-arm64-msvc": "12.3.2",
315 | "@next/swc-win32-ia32-msvc": "12.3.2",
316 | "@next/swc-win32-x64-msvc": "12.3.2"
317 | },
318 | "peerDependencies": {
319 | "fibers": ">= 3.1.0",
320 | "node-sass": "^6.0.0 || ^7.0.0",
321 | "react": "^17.0.2 || ^18.0.0-0",
322 | "react-dom": "^17.0.2 || ^18.0.0-0",
323 | "sass": "^1.3.0"
324 | },
325 | "peerDependenciesMeta": {
326 | "fibers": {
327 | "optional": true
328 | },
329 | "node-sass": {
330 | "optional": true
331 | },
332 | "sass": {
333 | "optional": true
334 | }
335 | }
336 | },
337 | "node_modules/next-router-mock": {
338 | "resolved": "../..",
339 | "link": true
340 | },
341 | "node_modules/picocolors": {
342 | "version": "1.0.0",
343 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
344 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
345 | },
346 | "node_modules/postcss": {
347 | "version": "8.4.14",
348 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
349 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
350 | "funding": [
351 | {
352 | "type": "opencollective",
353 | "url": "https://opencollective.com/postcss/"
354 | },
355 | {
356 | "type": "tidelift",
357 | "url": "https://tidelift.com/funding/github/npm/postcss"
358 | }
359 | ],
360 | "dependencies": {
361 | "nanoid": "^3.3.4",
362 | "picocolors": "^1.0.0",
363 | "source-map-js": "^1.0.2"
364 | },
365 | "engines": {
366 | "node": "^10 || ^12 || >=14"
367 | }
368 | },
369 | "node_modules/react": {
370 | "version": "18.1.0",
371 | "license": "MIT",
372 | "peer": true,
373 | "dependencies": {
374 | "loose-envify": "^1.1.0"
375 | },
376 | "engines": {
377 | "node": ">=0.10.0"
378 | }
379 | },
380 | "node_modules/react-dom": {
381 | "version": "18.1.0",
382 | "license": "MIT",
383 | "peer": true,
384 | "dependencies": {
385 | "loose-envify": "^1.1.0",
386 | "scheduler": "^0.22.0"
387 | },
388 | "peerDependencies": {
389 | "react": "^18.1.0"
390 | }
391 | },
392 | "node_modules/scheduler": {
393 | "version": "0.22.0",
394 | "license": "MIT",
395 | "peer": true,
396 | "dependencies": {
397 | "loose-envify": "^1.1.0"
398 | }
399 | },
400 | "node_modules/source-map-js": {
401 | "version": "1.0.2",
402 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
403 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
404 | "engines": {
405 | "node": ">=0.10.0"
406 | }
407 | },
408 | "node_modules/styled-jsx": {
409 | "version": "5.0.7",
410 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz",
411 | "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==",
412 | "engines": {
413 | "node": ">= 12.0.0"
414 | },
415 | "peerDependencies": {
416 | "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
417 | },
418 | "peerDependenciesMeta": {
419 | "@babel/core": {
420 | "optional": true
421 | },
422 | "babel-plugin-macros": {
423 | "optional": true
424 | }
425 | }
426 | },
427 | "node_modules/tslib": {
428 | "version": "2.4.1",
429 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
430 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
431 | },
432 | "node_modules/use-sync-external-store": {
433 | "version": "1.2.0",
434 | "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
435 | "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
436 | "peerDependencies": {
437 | "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
438 | }
439 | }
440 | },
441 | "dependencies": {
442 | "@next/env": {
443 | "version": "12.3.2",
444 | "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.2.tgz",
445 | "integrity": "sha512-upwtMaHxlv/udAWGq0kE+rg8huwmcxQPsKZFhS1R5iVO323mvxEBe1YrSXe1awLbg9sTIuEHbgxjLLt7JbeuAQ=="
446 | },
447 | "@next/swc-android-arm-eabi": {
448 | "version": "12.3.2",
449 | "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.2.tgz",
450 | "integrity": "sha512-r2rrz+DZ8YYGqzVrbRrpP6GKzwozpOrnFbErc4k36vUTSFMag9yQahZfaBe06JYdqu/e5yhm/saIDEaSVPRP4g==",
451 | "optional": true
452 | },
453 | "@next/swc-android-arm64": {
454 | "version": "12.3.2",
455 | "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.2.tgz",
456 | "integrity": "sha512-B+TINJhCf+CrY1+b3/JWQlkecv53rAGa/gA7gi5B1cnBa/2Uvoe+Ue0JeCefTjfiyl1ScsyNx+NcESY8Ye2Ngg==",
457 | "optional": true
458 | },
459 | "@next/swc-darwin-arm64": {
460 | "version": "12.3.2",
461 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.2.tgz",
462 | "integrity": "sha512-PTUfe1ZrwjsiuTmr3bOM9lsoy5DCmfYsLOUF9ZVhtbi5MNJVmUTy4VZ06GfrvnCO5hGCr48z3vpFE9QZ0qLcPw==",
463 | "optional": true
464 | },
465 | "@next/swc-darwin-x64": {
466 | "version": "12.3.2",
467 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.2.tgz",
468 | "integrity": "sha512-1HkjmS9awwlaeEY8Y01nRSNkSv3y+qnC/mjMPe/W66hEh3QKa/LQHqHeS7NOdEs19B2mhZ7w+EgMRXdLQ0Su8w==",
469 | "optional": true
470 | },
471 | "@next/swc-freebsd-x64": {
472 | "version": "12.3.2",
473 | "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.2.tgz",
474 | "integrity": "sha512-h5Mx0BKDCJ5Vu/U8e07esF6PjPv1EJgmRbYWTUZMAflu13MQpCJkKEJir7+BeRfTXRfgFf+llc7uocrpd7mcrg==",
475 | "optional": true
476 | },
477 | "@next/swc-linux-arm-gnueabihf": {
478 | "version": "12.3.2",
479 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.2.tgz",
480 | "integrity": "sha512-EuRZAamoxfe/WoWRaC0zsCAoE4gs/mEhilcloNM4J5Mnb3PLY8PZV394W7t5tjBjItMCF7l2Ebwjwtm46tq2RA==",
481 | "optional": true
482 | },
483 | "@next/swc-linux-arm64-gnu": {
484 | "version": "12.3.2",
485 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.2.tgz",
486 | "integrity": "sha512-T9GCFyOIb4S3acA9LqflUYD+QZ94iZketHCqKdoO0Nx0OCHIgGJV5rotDe8TDXwh/goYpIfyHU4j1qqw4w4VnA==",
487 | "optional": true
488 | },
489 | "@next/swc-linux-arm64-musl": {
490 | "version": "12.3.2",
491 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.2.tgz",
492 | "integrity": "sha512-hxNVZS6L3c2z3l9EH2GP0MGQ9exu6O8cohYNZyqC9WUl6C03sEn8xzDH1y+NgD3fVurvYkGU5F0PDddJJLfDIw==",
493 | "optional": true
494 | },
495 | "@next/swc-linux-x64-gnu": {
496 | "version": "12.3.2",
497 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.2.tgz",
498 | "integrity": "sha512-fCPkLuwDwY8/QeXxciJJjDHG09liZym/Bhb4A+RLFQ877wUkwFsNWDUTSdUx0YXlYK/1gf67BKauqKkOKp6CYw==",
499 | "optional": true
500 | },
501 | "@next/swc-linux-x64-musl": {
502 | "version": "12.3.2",
503 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.2.tgz",
504 | "integrity": "sha512-o+GifBIQ2K+/MEFxHsxUZoU3bsuVFLXZYWd3idimFHiVdDCVYiKsY6mYMmKDlucX+9xRyOCkKL9Tjf+3tuXJpw==",
505 | "optional": true
506 | },
507 | "@next/swc-win32-arm64-msvc": {
508 | "version": "12.3.2",
509 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.2.tgz",
510 | "integrity": "sha512-crii66irzGGMSUR0L8r9+A06eTv7FTXqw4rgzJ33M79EwQJOdpY7RVKXLQMurUhniEeQEEOfamiEdPIi/qxisw==",
511 | "optional": true
512 | },
513 | "@next/swc-win32-ia32-msvc": {
514 | "version": "12.3.2",
515 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.2.tgz",
516 | "integrity": "sha512-5hRUSvn3MdQ4nVRu1rmKxq5YJzpTtZfaC/NyGw6wa4NSF1noUn/pdQGUr+I5Qz3CZkd1gZzzC0eaXQHlrk0E2g==",
517 | "optional": true
518 | },
519 | "@next/swc-win32-x64-msvc": {
520 | "version": "12.3.2",
521 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.2.tgz",
522 | "integrity": "sha512-tpQJYUH+TzPMIsdVl9fH8uDg47iwiNjKY+8e9da3dXqlkztKzjSw0OwSADoqh3KrifplXeKSta+BBGLdBqg3sg==",
523 | "optional": true
524 | },
525 | "@swc/helpers": {
526 | "version": "0.4.11",
527 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
528 | "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==",
529 | "requires": {
530 | "tslib": "^2.4.0"
531 | }
532 | },
533 | "caniuse-lite": {
534 | "version": "1.0.30001431",
535 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
536 | "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ=="
537 | },
538 | "js-tokens": {
539 | "version": "4.0.0",
540 | "peer": true
541 | },
542 | "loose-envify": {
543 | "version": "1.4.0",
544 | "peer": true,
545 | "requires": {
546 | "js-tokens": "^3.0.0 || ^4.0.0"
547 | }
548 | },
549 | "nanoid": {
550 | "version": "3.3.4",
551 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
552 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
553 | },
554 | "next": {
555 | "version": "12.3.2",
556 | "resolved": "https://registry.npmjs.org/next/-/next-12.3.2.tgz",
557 | "integrity": "sha512-orzvvebCwOqaz1eA5ZA0R5dbKxqtJyw7yeig7kDspu6p8OrplfyelzpvMHcDTKscv/l0nn/0l0v3mSsE8w4k7A==",
558 | "requires": {
559 | "@next/env": "12.3.2",
560 | "@next/swc-android-arm-eabi": "12.3.2",
561 | "@next/swc-android-arm64": "12.3.2",
562 | "@next/swc-darwin-arm64": "12.3.2",
563 | "@next/swc-darwin-x64": "12.3.2",
564 | "@next/swc-freebsd-x64": "12.3.2",
565 | "@next/swc-linux-arm-gnueabihf": "12.3.2",
566 | "@next/swc-linux-arm64-gnu": "12.3.2",
567 | "@next/swc-linux-arm64-musl": "12.3.2",
568 | "@next/swc-linux-x64-gnu": "12.3.2",
569 | "@next/swc-linux-x64-musl": "12.3.2",
570 | "@next/swc-win32-arm64-msvc": "12.3.2",
571 | "@next/swc-win32-ia32-msvc": "12.3.2",
572 | "@next/swc-win32-x64-msvc": "12.3.2",
573 | "@swc/helpers": "0.4.11",
574 | "caniuse-lite": "^1.0.30001406",
575 | "postcss": "8.4.14",
576 | "styled-jsx": "5.0.7",
577 | "use-sync-external-store": "1.2.0"
578 | }
579 | },
580 | "next-router-mock": {
581 | "version": "file:../..",
582 | "requires": {
583 | "@changesets/cli": "^2.26.2",
584 | "@testing-library/react": "^13.4.0",
585 | "@types/jest": "^26.0.20",
586 | "doctoc": "^2.2.0",
587 | "jest": "^26.6.3",
588 | "next": "^13.5.1",
589 | "prettier": "^2.2.1",
590 | "react": "^18.2.0",
591 | "react-dom": "^18.2.0",
592 | "react-test-renderer": "^18.2.0",
593 | "rimraf": "^3.0.2",
594 | "ts-jest": "^26.4.4",
595 | "typescript": "^4.9.5"
596 | }
597 | },
598 | "picocolors": {
599 | "version": "1.0.0",
600 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
601 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
602 | },
603 | "postcss": {
604 | "version": "8.4.14",
605 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
606 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
607 | "requires": {
608 | "nanoid": "^3.3.4",
609 | "picocolors": "^1.0.0",
610 | "source-map-js": "^1.0.2"
611 | }
612 | },
613 | "react": {
614 | "version": "18.1.0",
615 | "peer": true,
616 | "requires": {
617 | "loose-envify": "^1.1.0"
618 | }
619 | },
620 | "react-dom": {
621 | "version": "18.1.0",
622 | "peer": true,
623 | "requires": {
624 | "loose-envify": "^1.1.0",
625 | "scheduler": "^0.22.0"
626 | }
627 | },
628 | "scheduler": {
629 | "version": "0.22.0",
630 | "peer": true,
631 | "requires": {
632 | "loose-envify": "^1.1.0"
633 | }
634 | },
635 | "source-map-js": {
636 | "version": "1.0.2",
637 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
638 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
639 | },
640 | "styled-jsx": {
641 | "version": "5.0.7",
642 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz",
643 | "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==",
644 | "requires": {}
645 | },
646 | "tslib": {
647 | "version": "2.4.1",
648 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
649 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
650 | },
651 | "use-sync-external-store": {
652 | "version": "1.2.0",
653 | "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
654 | "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
655 | "requires": {}
656 | }
657 | }
658 | }
659 |
--------------------------------------------------------------------------------
/test/next-12.2+/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "12.3.2",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/next-12.latest/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/test/next-12.latest/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-12.latest/next-12.latest.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-12";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-12";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-12", () => {
15 | require("next-router-mock/dynamic-routes/next-12");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-12", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-12");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-12.latest/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "12.*",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/next-12/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-12/next-12.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-12";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-12";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-12", () => {
15 | require("next-router-mock/dynamic-routes/next-12");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-12", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-12");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-12/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-12",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "next": "12.1.6",
9 | "next-router-mock": "../.."
10 | }
11 | },
12 | "../..": {
13 | "version": "1.0.0",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "@changesets/cli": "^2.26.2",
17 | "@testing-library/react": "^13.4.0",
18 | "@types/jest": "^26.0.20",
19 | "doctoc": "^2.2.0",
20 | "jest": "^26.6.3",
21 | "next": "^13.5.1",
22 | "prettier": "^2.2.1",
23 | "react": "^18.2.0",
24 | "react-dom": "^18.2.0",
25 | "react-test-renderer": "^18.2.0",
26 | "rimraf": "^3.0.2",
27 | "ts-jest": "^26.4.4",
28 | "typescript": "^4.9.5"
29 | },
30 | "peerDependencies": {
31 | "next": ">=10.0.0",
32 | "react": ">=17.0.0"
33 | }
34 | },
35 | "node_modules/@next/env": {
36 | "version": "12.1.6",
37 | "license": "MIT"
38 | },
39 | "node_modules/@next/swc-darwin-x64": {
40 | "version": "12.1.6",
41 | "cpu": [
42 | "x64"
43 | ],
44 | "license": "MIT",
45 | "optional": true,
46 | "os": [
47 | "darwin"
48 | ],
49 | "engines": {
50 | "node": ">= 10"
51 | }
52 | },
53 | "node_modules/caniuse-lite": {
54 | "version": "1.0.30001344",
55 | "funding": [
56 | {
57 | "type": "opencollective",
58 | "url": "https://opencollective.com/browserslist"
59 | },
60 | {
61 | "type": "tidelift",
62 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
63 | }
64 | ],
65 | "license": "CC-BY-4.0"
66 | },
67 | "node_modules/js-tokens": {
68 | "version": "4.0.0",
69 | "license": "MIT",
70 | "peer": true
71 | },
72 | "node_modules/loose-envify": {
73 | "version": "1.4.0",
74 | "license": "MIT",
75 | "peer": true,
76 | "dependencies": {
77 | "js-tokens": "^3.0.0 || ^4.0.0"
78 | },
79 | "bin": {
80 | "loose-envify": "cli.js"
81 | }
82 | },
83 | "node_modules/nanoid": {
84 | "version": "3.3.4",
85 | "license": "MIT",
86 | "bin": {
87 | "nanoid": "bin/nanoid.cjs"
88 | },
89 | "engines": {
90 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
91 | }
92 | },
93 | "node_modules/next": {
94 | "version": "12.1.6",
95 | "license": "MIT",
96 | "dependencies": {
97 | "@next/env": "12.1.6",
98 | "caniuse-lite": "^1.0.30001332",
99 | "postcss": "8.4.5",
100 | "styled-jsx": "5.0.2"
101 | },
102 | "bin": {
103 | "next": "dist/bin/next"
104 | },
105 | "engines": {
106 | "node": ">=12.22.0"
107 | },
108 | "optionalDependencies": {
109 | "@next/swc-android-arm-eabi": "12.1.6",
110 | "@next/swc-android-arm64": "12.1.6",
111 | "@next/swc-darwin-arm64": "12.1.6",
112 | "@next/swc-darwin-x64": "12.1.6",
113 | "@next/swc-linux-arm-gnueabihf": "12.1.6",
114 | "@next/swc-linux-arm64-gnu": "12.1.6",
115 | "@next/swc-linux-arm64-musl": "12.1.6",
116 | "@next/swc-linux-x64-gnu": "12.1.6",
117 | "@next/swc-linux-x64-musl": "12.1.6",
118 | "@next/swc-win32-arm64-msvc": "12.1.6",
119 | "@next/swc-win32-ia32-msvc": "12.1.6",
120 | "@next/swc-win32-x64-msvc": "12.1.6"
121 | },
122 | "peerDependencies": {
123 | "fibers": ">= 3.1.0",
124 | "node-sass": "^6.0.0 || ^7.0.0",
125 | "react": "^17.0.2 || ^18.0.0-0",
126 | "react-dom": "^17.0.2 || ^18.0.0-0",
127 | "sass": "^1.3.0"
128 | },
129 | "peerDependenciesMeta": {
130 | "fibers": {
131 | "optional": true
132 | },
133 | "node-sass": {
134 | "optional": true
135 | },
136 | "sass": {
137 | "optional": true
138 | }
139 | }
140 | },
141 | "node_modules/next-router-mock": {
142 | "resolved": "../..",
143 | "link": true
144 | },
145 | "node_modules/picocolors": {
146 | "version": "1.0.0",
147 | "license": "ISC"
148 | },
149 | "node_modules/postcss": {
150 | "version": "8.4.5",
151 | "license": "MIT",
152 | "dependencies": {
153 | "nanoid": "^3.1.30",
154 | "picocolors": "^1.0.0",
155 | "source-map-js": "^1.0.1"
156 | },
157 | "engines": {
158 | "node": "^10 || ^12 || >=14"
159 | },
160 | "funding": {
161 | "type": "opencollective",
162 | "url": "https://opencollective.com/postcss/"
163 | }
164 | },
165 | "node_modules/react": {
166 | "version": "18.1.0",
167 | "license": "MIT",
168 | "peer": true,
169 | "dependencies": {
170 | "loose-envify": "^1.1.0"
171 | },
172 | "engines": {
173 | "node": ">=0.10.0"
174 | }
175 | },
176 | "node_modules/react-dom": {
177 | "version": "18.1.0",
178 | "license": "MIT",
179 | "peer": true,
180 | "dependencies": {
181 | "loose-envify": "^1.1.0",
182 | "scheduler": "^0.22.0"
183 | },
184 | "peerDependencies": {
185 | "react": "^18.1.0"
186 | }
187 | },
188 | "node_modules/scheduler": {
189 | "version": "0.22.0",
190 | "license": "MIT",
191 | "peer": true,
192 | "dependencies": {
193 | "loose-envify": "^1.1.0"
194 | }
195 | },
196 | "node_modules/source-map-js": {
197 | "version": "1.0.2",
198 | "license": "BSD-3-Clause",
199 | "engines": {
200 | "node": ">=0.10.0"
201 | }
202 | },
203 | "node_modules/styled-jsx": {
204 | "version": "5.0.2",
205 | "license": "MIT",
206 | "engines": {
207 | "node": ">= 12.0.0"
208 | },
209 | "peerDependencies": {
210 | "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
211 | },
212 | "peerDependenciesMeta": {
213 | "@babel/core": {
214 | "optional": true
215 | },
216 | "babel-plugin-macros": {
217 | "optional": true
218 | }
219 | }
220 | }
221 | },
222 | "dependencies": {
223 | "@next/env": {
224 | "version": "12.1.6"
225 | },
226 | "@next/swc-darwin-x64": {
227 | "version": "12.1.6",
228 | "optional": true
229 | },
230 | "caniuse-lite": {
231 | "version": "1.0.30001344"
232 | },
233 | "js-tokens": {
234 | "version": "4.0.0",
235 | "peer": true
236 | },
237 | "loose-envify": {
238 | "version": "1.4.0",
239 | "peer": true,
240 | "requires": {
241 | "js-tokens": "^3.0.0 || ^4.0.0"
242 | }
243 | },
244 | "nanoid": {
245 | "version": "3.3.4"
246 | },
247 | "next": {
248 | "version": "12.1.6",
249 | "requires": {
250 | "@next/env": "12.1.6",
251 | "@next/swc-android-arm-eabi": "12.1.6",
252 | "@next/swc-android-arm64": "12.1.6",
253 | "@next/swc-darwin-arm64": "12.1.6",
254 | "@next/swc-darwin-x64": "12.1.6",
255 | "@next/swc-linux-arm-gnueabihf": "12.1.6",
256 | "@next/swc-linux-arm64-gnu": "12.1.6",
257 | "@next/swc-linux-arm64-musl": "12.1.6",
258 | "@next/swc-linux-x64-gnu": "12.1.6",
259 | "@next/swc-linux-x64-musl": "12.1.6",
260 | "@next/swc-win32-arm64-msvc": "12.1.6",
261 | "@next/swc-win32-ia32-msvc": "12.1.6",
262 | "@next/swc-win32-x64-msvc": "12.1.6",
263 | "caniuse-lite": "^1.0.30001332",
264 | "postcss": "8.4.5",
265 | "styled-jsx": "5.0.2"
266 | }
267 | },
268 | "next-router-mock": {
269 | "version": "file:../..",
270 | "requires": {
271 | "@changesets/cli": "^2.26.2",
272 | "@testing-library/react": "^13.4.0",
273 | "@types/jest": "^26.0.20",
274 | "doctoc": "^2.2.0",
275 | "jest": "^26.6.3",
276 | "next": "^13.5.1",
277 | "prettier": "^2.2.1",
278 | "react": "^18.2.0",
279 | "react-dom": "^18.2.0",
280 | "react-test-renderer": "^18.2.0",
281 | "rimraf": "^3.0.2",
282 | "ts-jest": "^26.4.4",
283 | "typescript": "^4.9.5"
284 | }
285 | },
286 | "picocolors": {
287 | "version": "1.0.0"
288 | },
289 | "postcss": {
290 | "version": "8.4.5",
291 | "requires": {
292 | "nanoid": "^3.1.30",
293 | "picocolors": "^1.0.0",
294 | "source-map-js": "^1.0.1"
295 | }
296 | },
297 | "react": {
298 | "version": "18.1.0",
299 | "peer": true,
300 | "requires": {
301 | "loose-envify": "^1.1.0"
302 | }
303 | },
304 | "react-dom": {
305 | "version": "18.1.0",
306 | "peer": true,
307 | "requires": {
308 | "loose-envify": "^1.1.0",
309 | "scheduler": "^0.22.0"
310 | }
311 | },
312 | "scheduler": {
313 | "version": "0.22.0",
314 | "peer": true,
315 | "requires": {
316 | "loose-envify": "^1.1.0"
317 | }
318 | },
319 | "source-map-js": {
320 | "version": "1.0.2"
321 | },
322 | "styled-jsx": {
323 | "version": "5.0.2",
324 | "requires": {}
325 | }
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/test/next-12/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "12.1.6",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/next-13.5/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-13.5/next-13.5.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-13";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-13.5";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-13", () => {
15 | require("next-router-mock/dynamic-routes/next-13");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-13", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-13.5");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-13.5/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-13.5",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "next": "13.5.1",
9 | "next-router-mock": "../.."
10 | }
11 | },
12 | "../..": {
13 | "version": "1.0.0",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "@changesets/cli": "^2.26.2",
17 | "@testing-library/react": "^13.4.0",
18 | "@types/jest": "^26.0.20",
19 | "doctoc": "^2.2.0",
20 | "jest": "^26.6.3",
21 | "next": "^13.5.1",
22 | "prettier": "^2.2.1",
23 | "react": "^18.2.0",
24 | "react-dom": "^18.2.0",
25 | "react-test-renderer": "^18.2.0",
26 | "rimraf": "^3.0.2",
27 | "ts-jest": "^26.4.4",
28 | "typescript": "^4.9.5"
29 | },
30 | "peerDependencies": {
31 | "next": ">=10.0.0",
32 | "react": ">=17.0.0"
33 | }
34 | },
35 | "node_modules/@next/env": {
36 | "version": "13.5.1",
37 | "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.1.tgz",
38 | "integrity": "sha512-CIMWiOTyflFn/GFx33iYXkgLSQsMQZV4jB91qaj/TfxGaGOXxn8C1j72TaUSPIyN7ziS/AYG46kGmnvuk1oOpg=="
39 | },
40 | "node_modules/@next/swc-darwin-arm64": {
41 | "version": "13.5.1",
42 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.1.tgz",
43 | "integrity": "sha512-Bcd0VFrLHZnMmJy6LqV1CydZ7lYaBao8YBEdQUVzV8Ypn/l5s//j5ffjfvMzpEQ4mzlAj3fIY+Bmd9NxpWhACw==",
44 | "cpu": [
45 | "arm64"
46 | ],
47 | "optional": true,
48 | "os": [
49 | "darwin"
50 | ],
51 | "engines": {
52 | "node": ">= 10"
53 | }
54 | },
55 | "node_modules/@next/swc-darwin-x64": {
56 | "version": "13.5.1",
57 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.1.tgz",
58 | "integrity": "sha512-uvTZrZa4D0bdWa1jJ7X1tBGIxzpqSnw/ATxWvoRO9CVBvXSx87JyuISY+BWsfLFF59IRodESdeZwkWM2l6+Kjg==",
59 | "cpu": [
60 | "x64"
61 | ],
62 | "optional": true,
63 | "os": [
64 | "darwin"
65 | ],
66 | "engines": {
67 | "node": ">= 10"
68 | }
69 | },
70 | "node_modules/@next/swc-linux-arm64-gnu": {
71 | "version": "13.5.1",
72 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.1.tgz",
73 | "integrity": "sha512-/52ThlqdORPQt3+AlMoO+omicdYyUEDeRDGPAj86ULpV4dg+/GCFCKAmFWT0Q4zChFwsAoZUECLcKbRdcc0SNg==",
74 | "cpu": [
75 | "arm64"
76 | ],
77 | "optional": true,
78 | "os": [
79 | "linux"
80 | ],
81 | "engines": {
82 | "node": ">= 10"
83 | }
84 | },
85 | "node_modules/@next/swc-linux-arm64-musl": {
86 | "version": "13.5.1",
87 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.1.tgz",
88 | "integrity": "sha512-L4qNXSOHeu1hEAeeNsBgIYVnvm0gg9fj2O2Yx/qawgQEGuFBfcKqlmIE/Vp8z6gwlppxz5d7v6pmHs1NB6R37w==",
89 | "cpu": [
90 | "arm64"
91 | ],
92 | "optional": true,
93 | "os": [
94 | "linux"
95 | ],
96 | "engines": {
97 | "node": ">= 10"
98 | }
99 | },
100 | "node_modules/@next/swc-linux-x64-gnu": {
101 | "version": "13.5.1",
102 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.1.tgz",
103 | "integrity": "sha512-QVvMrlrFFYvLtABk092kcZ5Mzlmsk2+SV3xYuAu8sbTuIoh0U2+HGNhVklmuYCuM3DAAxdiMQTNlRQmNH11udw==",
104 | "cpu": [
105 | "x64"
106 | ],
107 | "optional": true,
108 | "os": [
109 | "linux"
110 | ],
111 | "engines": {
112 | "node": ">= 10"
113 | }
114 | },
115 | "node_modules/@next/swc-linux-x64-musl": {
116 | "version": "13.5.1",
117 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.1.tgz",
118 | "integrity": "sha512-bBnr+XuWc28r9e8gQ35XBtyi5KLHLhTbEvrSgcWna8atI48sNggjIK8IyiEBO3KIrcUVXYkldAzGXPEYMnKt1g==",
119 | "cpu": [
120 | "x64"
121 | ],
122 | "optional": true,
123 | "os": [
124 | "linux"
125 | ],
126 | "engines": {
127 | "node": ">= 10"
128 | }
129 | },
130 | "node_modules/@next/swc-win32-arm64-msvc": {
131 | "version": "13.5.1",
132 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.1.tgz",
133 | "integrity": "sha512-EQGeE4S5c9v06jje9gr4UlxqUEA+zrsgPi6kg9VwR+dQHirzbnVJISF69UfKVkmLntknZJJI9XpWPB6q0Z7mTg==",
134 | "cpu": [
135 | "arm64"
136 | ],
137 | "optional": true,
138 | "os": [
139 | "win32"
140 | ],
141 | "engines": {
142 | "node": ">= 10"
143 | }
144 | },
145 | "node_modules/@next/swc-win32-ia32-msvc": {
146 | "version": "13.5.1",
147 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.1.tgz",
148 | "integrity": "sha512-1y31Q6awzofVjmbTLtRl92OX3s+W0ZfO8AP8fTnITcIo9a6ATDc/eqa08fd6tSpFu6IFpxOBbdevOjwYTGx/AQ==",
149 | "cpu": [
150 | "ia32"
151 | ],
152 | "optional": true,
153 | "os": [
154 | "win32"
155 | ],
156 | "engines": {
157 | "node": ">= 10"
158 | }
159 | },
160 | "node_modules/@next/swc-win32-x64-msvc": {
161 | "version": "13.5.1",
162 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.1.tgz",
163 | "integrity": "sha512-+9XBQizy7X/GuwNegq+5QkkxAPV7SBsIwapVRQd9WSvvU20YO23B3bZUpevdabi4fsd25y9RJDDncljy/V54ww==",
164 | "cpu": [
165 | "x64"
166 | ],
167 | "optional": true,
168 | "os": [
169 | "win32"
170 | ],
171 | "engines": {
172 | "node": ">= 10"
173 | }
174 | },
175 | "node_modules/@swc/helpers": {
176 | "version": "0.5.2",
177 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
178 | "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
179 | "dependencies": {
180 | "tslib": "^2.4.0"
181 | }
182 | },
183 | "node_modules/busboy": {
184 | "version": "1.6.0",
185 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
186 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
187 | "dependencies": {
188 | "streamsearch": "^1.1.0"
189 | },
190 | "engines": {
191 | "node": ">=10.16.0"
192 | }
193 | },
194 | "node_modules/caniuse-lite": {
195 | "version": "1.0.30001431",
196 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
197 | "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==",
198 | "funding": [
199 | {
200 | "type": "opencollective",
201 | "url": "https://opencollective.com/browserslist"
202 | },
203 | {
204 | "type": "tidelift",
205 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
206 | }
207 | ]
208 | },
209 | "node_modules/client-only": {
210 | "version": "0.0.1",
211 | "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
212 | "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
213 | },
214 | "node_modules/glob-to-regexp": {
215 | "version": "0.4.1",
216 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
217 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
218 | },
219 | "node_modules/graceful-fs": {
220 | "version": "4.2.11",
221 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
222 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
223 | },
224 | "node_modules/js-tokens": {
225 | "version": "4.0.0",
226 | "license": "MIT",
227 | "peer": true
228 | },
229 | "node_modules/loose-envify": {
230 | "version": "1.4.0",
231 | "license": "MIT",
232 | "peer": true,
233 | "dependencies": {
234 | "js-tokens": "^3.0.0 || ^4.0.0"
235 | },
236 | "bin": {
237 | "loose-envify": "cli.js"
238 | }
239 | },
240 | "node_modules/nanoid": {
241 | "version": "3.3.4",
242 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
243 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
244 | "bin": {
245 | "nanoid": "bin/nanoid.cjs"
246 | },
247 | "engines": {
248 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
249 | }
250 | },
251 | "node_modules/next": {
252 | "version": "13.5.1",
253 | "resolved": "https://registry.npmjs.org/next/-/next-13.5.1.tgz",
254 | "integrity": "sha512-GIudNR7ggGUZoIL79mSZcxbXK9f5pwAIPZxEM8+j2yLqv5RODg4TkmUlaKSYVqE1bPQueamXSqdC3j7axiTSEg==",
255 | "dependencies": {
256 | "@next/env": "13.5.1",
257 | "@swc/helpers": "0.5.2",
258 | "busboy": "1.6.0",
259 | "caniuse-lite": "^1.0.30001406",
260 | "postcss": "8.4.14",
261 | "styled-jsx": "5.1.1",
262 | "watchpack": "2.4.0",
263 | "zod": "3.21.4"
264 | },
265 | "bin": {
266 | "next": "dist/bin/next"
267 | },
268 | "engines": {
269 | "node": ">=16.14.0"
270 | },
271 | "optionalDependencies": {
272 | "@next/swc-darwin-arm64": "13.5.1",
273 | "@next/swc-darwin-x64": "13.5.1",
274 | "@next/swc-linux-arm64-gnu": "13.5.1",
275 | "@next/swc-linux-arm64-musl": "13.5.1",
276 | "@next/swc-linux-x64-gnu": "13.5.1",
277 | "@next/swc-linux-x64-musl": "13.5.1",
278 | "@next/swc-win32-arm64-msvc": "13.5.1",
279 | "@next/swc-win32-ia32-msvc": "13.5.1",
280 | "@next/swc-win32-x64-msvc": "13.5.1"
281 | },
282 | "peerDependencies": {
283 | "@opentelemetry/api": "^1.1.0",
284 | "react": "^18.2.0",
285 | "react-dom": "^18.2.0",
286 | "sass": "^1.3.0"
287 | },
288 | "peerDependenciesMeta": {
289 | "@opentelemetry/api": {
290 | "optional": true
291 | },
292 | "sass": {
293 | "optional": true
294 | }
295 | }
296 | },
297 | "node_modules/next-router-mock": {
298 | "resolved": "../..",
299 | "link": true
300 | },
301 | "node_modules/picocolors": {
302 | "version": "1.0.0",
303 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
304 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
305 | },
306 | "node_modules/postcss": {
307 | "version": "8.4.14",
308 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
309 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
310 | "funding": [
311 | {
312 | "type": "opencollective",
313 | "url": "https://opencollective.com/postcss/"
314 | },
315 | {
316 | "type": "tidelift",
317 | "url": "https://tidelift.com/funding/github/npm/postcss"
318 | }
319 | ],
320 | "dependencies": {
321 | "nanoid": "^3.3.4",
322 | "picocolors": "^1.0.0",
323 | "source-map-js": "^1.0.2"
324 | },
325 | "engines": {
326 | "node": "^10 || ^12 || >=14"
327 | }
328 | },
329 | "node_modules/react": {
330 | "version": "18.2.0",
331 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
332 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
333 | "peer": true,
334 | "dependencies": {
335 | "loose-envify": "^1.1.0"
336 | },
337 | "engines": {
338 | "node": ">=0.10.0"
339 | }
340 | },
341 | "node_modules/react-dom": {
342 | "version": "18.2.0",
343 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
344 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
345 | "peer": true,
346 | "dependencies": {
347 | "loose-envify": "^1.1.0",
348 | "scheduler": "^0.23.0"
349 | },
350 | "peerDependencies": {
351 | "react": "^18.2.0"
352 | }
353 | },
354 | "node_modules/scheduler": {
355 | "version": "0.23.0",
356 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
357 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
358 | "peer": true,
359 | "dependencies": {
360 | "loose-envify": "^1.1.0"
361 | }
362 | },
363 | "node_modules/source-map-js": {
364 | "version": "1.0.2",
365 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
366 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
367 | "engines": {
368 | "node": ">=0.10.0"
369 | }
370 | },
371 | "node_modules/streamsearch": {
372 | "version": "1.1.0",
373 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
374 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
375 | "engines": {
376 | "node": ">=10.0.0"
377 | }
378 | },
379 | "node_modules/styled-jsx": {
380 | "version": "5.1.1",
381 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
382 | "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
383 | "dependencies": {
384 | "client-only": "0.0.1"
385 | },
386 | "engines": {
387 | "node": ">= 12.0.0"
388 | },
389 | "peerDependencies": {
390 | "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
391 | },
392 | "peerDependenciesMeta": {
393 | "@babel/core": {
394 | "optional": true
395 | },
396 | "babel-plugin-macros": {
397 | "optional": true
398 | }
399 | }
400 | },
401 | "node_modules/tslib": {
402 | "version": "2.6.2",
403 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
404 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
405 | },
406 | "node_modules/watchpack": {
407 | "version": "2.4.0",
408 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
409 | "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
410 | "dependencies": {
411 | "glob-to-regexp": "^0.4.1",
412 | "graceful-fs": "^4.1.2"
413 | },
414 | "engines": {
415 | "node": ">=10.13.0"
416 | }
417 | },
418 | "node_modules/zod": {
419 | "version": "3.21.4",
420 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
421 | "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
422 | "funding": {
423 | "url": "https://github.com/sponsors/colinhacks"
424 | }
425 | }
426 | },
427 | "dependencies": {
428 | "@next/env": {
429 | "version": "13.5.1",
430 | "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.1.tgz",
431 | "integrity": "sha512-CIMWiOTyflFn/GFx33iYXkgLSQsMQZV4jB91qaj/TfxGaGOXxn8C1j72TaUSPIyN7ziS/AYG46kGmnvuk1oOpg=="
432 | },
433 | "@next/swc-darwin-arm64": {
434 | "version": "13.5.1",
435 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.1.tgz",
436 | "integrity": "sha512-Bcd0VFrLHZnMmJy6LqV1CydZ7lYaBao8YBEdQUVzV8Ypn/l5s//j5ffjfvMzpEQ4mzlAj3fIY+Bmd9NxpWhACw==",
437 | "optional": true
438 | },
439 | "@next/swc-darwin-x64": {
440 | "version": "13.5.1",
441 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.1.tgz",
442 | "integrity": "sha512-uvTZrZa4D0bdWa1jJ7X1tBGIxzpqSnw/ATxWvoRO9CVBvXSx87JyuISY+BWsfLFF59IRodESdeZwkWM2l6+Kjg==",
443 | "optional": true
444 | },
445 | "@next/swc-linux-arm64-gnu": {
446 | "version": "13.5.1",
447 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.1.tgz",
448 | "integrity": "sha512-/52ThlqdORPQt3+AlMoO+omicdYyUEDeRDGPAj86ULpV4dg+/GCFCKAmFWT0Q4zChFwsAoZUECLcKbRdcc0SNg==",
449 | "optional": true
450 | },
451 | "@next/swc-linux-arm64-musl": {
452 | "version": "13.5.1",
453 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.1.tgz",
454 | "integrity": "sha512-L4qNXSOHeu1hEAeeNsBgIYVnvm0gg9fj2O2Yx/qawgQEGuFBfcKqlmIE/Vp8z6gwlppxz5d7v6pmHs1NB6R37w==",
455 | "optional": true
456 | },
457 | "@next/swc-linux-x64-gnu": {
458 | "version": "13.5.1",
459 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.1.tgz",
460 | "integrity": "sha512-QVvMrlrFFYvLtABk092kcZ5Mzlmsk2+SV3xYuAu8sbTuIoh0U2+HGNhVklmuYCuM3DAAxdiMQTNlRQmNH11udw==",
461 | "optional": true
462 | },
463 | "@next/swc-linux-x64-musl": {
464 | "version": "13.5.1",
465 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.1.tgz",
466 | "integrity": "sha512-bBnr+XuWc28r9e8gQ35XBtyi5KLHLhTbEvrSgcWna8atI48sNggjIK8IyiEBO3KIrcUVXYkldAzGXPEYMnKt1g==",
467 | "optional": true
468 | },
469 | "@next/swc-win32-arm64-msvc": {
470 | "version": "13.5.1",
471 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.1.tgz",
472 | "integrity": "sha512-EQGeE4S5c9v06jje9gr4UlxqUEA+zrsgPi6kg9VwR+dQHirzbnVJISF69UfKVkmLntknZJJI9XpWPB6q0Z7mTg==",
473 | "optional": true
474 | },
475 | "@next/swc-win32-ia32-msvc": {
476 | "version": "13.5.1",
477 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.1.tgz",
478 | "integrity": "sha512-1y31Q6awzofVjmbTLtRl92OX3s+W0ZfO8AP8fTnITcIo9a6ATDc/eqa08fd6tSpFu6IFpxOBbdevOjwYTGx/AQ==",
479 | "optional": true
480 | },
481 | "@next/swc-win32-x64-msvc": {
482 | "version": "13.5.1",
483 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.1.tgz",
484 | "integrity": "sha512-+9XBQizy7X/GuwNegq+5QkkxAPV7SBsIwapVRQd9WSvvU20YO23B3bZUpevdabi4fsd25y9RJDDncljy/V54ww==",
485 | "optional": true
486 | },
487 | "@swc/helpers": {
488 | "version": "0.5.2",
489 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
490 | "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
491 | "requires": {
492 | "tslib": "^2.4.0"
493 | }
494 | },
495 | "busboy": {
496 | "version": "1.6.0",
497 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
498 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
499 | "requires": {
500 | "streamsearch": "^1.1.0"
501 | }
502 | },
503 | "caniuse-lite": {
504 | "version": "1.0.30001431",
505 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
506 | "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ=="
507 | },
508 | "client-only": {
509 | "version": "0.0.1",
510 | "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
511 | "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
512 | },
513 | "glob-to-regexp": {
514 | "version": "0.4.1",
515 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
516 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
517 | },
518 | "graceful-fs": {
519 | "version": "4.2.11",
520 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
521 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
522 | },
523 | "js-tokens": {
524 | "version": "4.0.0",
525 | "peer": true
526 | },
527 | "loose-envify": {
528 | "version": "1.4.0",
529 | "peer": true,
530 | "requires": {
531 | "js-tokens": "^3.0.0 || ^4.0.0"
532 | }
533 | },
534 | "nanoid": {
535 | "version": "3.3.4",
536 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
537 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
538 | },
539 | "next": {
540 | "version": "13.5.1",
541 | "resolved": "https://registry.npmjs.org/next/-/next-13.5.1.tgz",
542 | "integrity": "sha512-GIudNR7ggGUZoIL79mSZcxbXK9f5pwAIPZxEM8+j2yLqv5RODg4TkmUlaKSYVqE1bPQueamXSqdC3j7axiTSEg==",
543 | "requires": {
544 | "@next/env": "13.5.1",
545 | "@next/swc-darwin-arm64": "13.5.1",
546 | "@next/swc-darwin-x64": "13.5.1",
547 | "@next/swc-linux-arm64-gnu": "13.5.1",
548 | "@next/swc-linux-arm64-musl": "13.5.1",
549 | "@next/swc-linux-x64-gnu": "13.5.1",
550 | "@next/swc-linux-x64-musl": "13.5.1",
551 | "@next/swc-win32-arm64-msvc": "13.5.1",
552 | "@next/swc-win32-ia32-msvc": "13.5.1",
553 | "@next/swc-win32-x64-msvc": "13.5.1",
554 | "@swc/helpers": "0.5.2",
555 | "busboy": "1.6.0",
556 | "caniuse-lite": "^1.0.30001406",
557 | "postcss": "8.4.14",
558 | "styled-jsx": "5.1.1",
559 | "watchpack": "2.4.0",
560 | "zod": "3.21.4"
561 | }
562 | },
563 | "next-router-mock": {
564 | "version": "file:../..",
565 | "requires": {
566 | "@changesets/cli": "^2.26.2",
567 | "@testing-library/react": "^13.4.0",
568 | "@types/jest": "^26.0.20",
569 | "doctoc": "^2.2.0",
570 | "jest": "^26.6.3",
571 | "next": "^13.5.1",
572 | "prettier": "^2.2.1",
573 | "react": "^18.2.0",
574 | "react-dom": "^18.2.0",
575 | "react-test-renderer": "^18.2.0",
576 | "rimraf": "^3.0.2",
577 | "ts-jest": "^26.4.4",
578 | "typescript": "^4.9.5"
579 | }
580 | },
581 | "picocolors": {
582 | "version": "1.0.0",
583 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
584 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
585 | },
586 | "postcss": {
587 | "version": "8.4.14",
588 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
589 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
590 | "requires": {
591 | "nanoid": "^3.3.4",
592 | "picocolors": "^1.0.0",
593 | "source-map-js": "^1.0.2"
594 | }
595 | },
596 | "react": {
597 | "version": "18.2.0",
598 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
599 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
600 | "peer": true,
601 | "requires": {
602 | "loose-envify": "^1.1.0"
603 | }
604 | },
605 | "react-dom": {
606 | "version": "18.2.0",
607 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
608 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
609 | "peer": true,
610 | "requires": {
611 | "loose-envify": "^1.1.0",
612 | "scheduler": "^0.23.0"
613 | }
614 | },
615 | "scheduler": {
616 | "version": "0.23.0",
617 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
618 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
619 | "peer": true,
620 | "requires": {
621 | "loose-envify": "^1.1.0"
622 | }
623 | },
624 | "source-map-js": {
625 | "version": "1.0.2",
626 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
627 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
628 | },
629 | "streamsearch": {
630 | "version": "1.1.0",
631 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
632 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
633 | },
634 | "styled-jsx": {
635 | "version": "5.1.1",
636 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
637 | "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
638 | "requires": {
639 | "client-only": "0.0.1"
640 | }
641 | },
642 | "tslib": {
643 | "version": "2.6.2",
644 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
645 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
646 | },
647 | "watchpack": {
648 | "version": "2.4.0",
649 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
650 | "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
651 | "requires": {
652 | "glob-to-regexp": "^0.4.1",
653 | "graceful-fs": "^4.1.2"
654 | }
655 | },
656 | "zod": {
657 | "version": "3.21.4",
658 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
659 | "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw=="
660 | }
661 | }
662 | }
663 |
--------------------------------------------------------------------------------
/test/next-13.5/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "13.5.1",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/next-13/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | moduleNameMapper: {
5 | // Ensure we "lock" the next version for these tests:
6 | "^next/(.*)$": "/node_modules/next/$1",
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/test/next-13/next-13.test.ts:
--------------------------------------------------------------------------------
1 | // Validate our types are exported correctly:
2 | import type { memoryRouter } from "next-router-mock";
3 | import type { memoryRouter as ___ } from "next-router-mock/async";
4 | import type { createDynamicRouteParser } from "next-router-mock/dynamic-routes";
5 | import type { createDynamicRouteParser as _ } from "next-router-mock/dynamic-routes/next-13";
6 | import type { MemoryRouterProvider } from "next-router-mock/MemoryRouterProvider";
7 | import type { MemoryRouterProvider as __ } from "next-router-mock/MemoryRouterProvider/next-13";
8 |
9 | describe(`next version ${require("next/package.json").version}`, () => {
10 | describe("automatic and explicit import paths are valid", () => {
11 | it("next-router-mock/dynamic-routes", () => {
12 | require("next-router-mock/dynamic-routes");
13 | });
14 | it("next-router-mock/dynamic-routes/next-13", () => {
15 | require("next-router-mock/dynamic-routes/next-13");
16 | });
17 | it("next-router-mock/MemoryRouterProvider", () => {
18 | require("next-router-mock/MemoryRouterProvider");
19 | });
20 | it("next-router-mock/MemoryRouterProvider/next-13", () => {
21 | require("next-router-mock/MemoryRouterProvider/next-13");
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/next-13/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "next": "13.0.2",
4 | "next-router-mock": "../.."
5 | },
6 | "scripts": {
7 | "test": "tsc && jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/test-exports/exports.test.ts:
--------------------------------------------------------------------------------
1 | import router, { useRouter } from "next/router";
2 | import { memoryRouter, MemoryRouter } from "../..";
3 | import { createDynamicRouteParser } from "../../dynamic-routes";
4 | import { MemoryRouterProvider } from "../../MemoryRouterProvider";
5 |
6 | jest.mock("next/router", () => require("../.."));
7 |
8 | describe("exports", () => {
9 | it("next/router should be exported correctly", () => {
10 | expect(router).toBeInstanceOf(MemoryRouter);
11 | expect(router).toBe(memoryRouter);
12 | expect(useRouter).toBeInstanceOf(Function);
13 | });
14 | describe("next-router-mock/dynamic-routes", () => {
15 | it("should be exported correctly", () => {
16 | expect(createDynamicRouteParser).toBeInstanceOf(Function);
17 | });
18 | });
19 | describe("next-router-mock/MemoryRouterProvider", () => {
20 | it("should be exported correctly", () => {
21 | expect(MemoryRouterProvider).toBeInstanceOf(Function);
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/test-exports/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | rootDir: ".",
4 | };
5 |
--------------------------------------------------------------------------------
/test/test-exports/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "test": "jest"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/test/test-utils.ts:
--------------------------------------------------------------------------------
1 | import type { MemoryRouter } from "../src/MemoryRouter";
2 |
3 | /**
4 | * Performs a partial equality comparison.
5 | *
6 | * This is similar to using `toMatchObject`, but doesn't ignore missing `query: { ... }` values!
7 | */
8 | export function expectMatch(memoryRouter: MemoryRouter, expected: Partial): void {
9 | const picked = pick(memoryRouter, Object.keys(expected) as Array);
10 | try {
11 | expect(picked).toEqual(expected);
12 | } catch (err: any) {
13 | // Ensure stack trace is accurate:
14 | Error.captureStackTrace(err, expectMatch);
15 | throw err;
16 | }
17 | }
18 |
19 | function pick(obj: T, keys: Array): T {
20 | const result = {} as T;
21 | keys.forEach((key) => {
22 | result[key] = obj[key];
23 | });
24 | return result;
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "dist",
5 | "rootDir": "src",
6 | "noEmit": false
7 | },
8 | "exclude": [
9 | "**/*.test.*",
10 | "test/**"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
8 | "module": "NodeNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
9 | "lib": ["ES2019", "DOM", "DOM.Iterable"], /* Specify library files to be included in the compilation. */
10 | // "allowJs": true, /* Allow javascript files to be compiled. */
11 | // "checkJs": true, /* Report errors in .js files. */
12 | "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
13 | "declaration": true, /* Generates corresponding '.d.ts' file. */
14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
15 | "sourceMap": true, /* Generates corresponding '.map' file. */
16 | // "outFile": "./", /* Concatenate and emit output to single file. */
17 | // "outDir": "dist", /* Redirect output structure to the directory. */
18 | // "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19 | // "composite": true, /* Enable project compilation */
20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
21 | // "removeComments": true, /* Do not emit comments to output. */
22 | "noEmit": true, /* Do not emit outputs. */
23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26 |
27 | /* Strict Type-Checking Options */
28 | "strict": true, /* Enable all strict type-checking options. */
29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
30 | // "strictNullChecks": true, /* Enable strict null checks. */
31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
36 |
37 | /* Additional Checks */
38 | // "noUnusedLocals": true, /* Report errors on unused locals. */
39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
43 |
44 | /* Module Resolution Options */
45 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
46 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
47 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
48 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
49 | // "typeRoots": [], /* List of folders to include type definitions from. */
50 | // "types": [], /* Type declaration files to be included in compilation. */
51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
52 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
55 |
56 | /* Source Map Options */
57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
61 |
62 | /* Experimental Options */
63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
65 |
66 | /* Advanced Options */
67 | "skipLibCheck": true, /* Skip type checking of declaration files. */
68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
69 | },
70 | "exclude": ["test/example-app"]
71 | }
72 |
--------------------------------------------------------------------------------