diff --git a/.changeset/healthy-clouds-check.md b/.changeset/healthy-clouds-check.md new file mode 100644 index 0000000..2a80359 --- /dev/null +++ b/.changeset/healthy-clouds-check.md @@ -0,0 +1,7 @@ +--- +"next-router-mock": minor +--- + +# Next 13 App Router Support +- Adds support for mocking `next/navigation` +- Adds `mockRouter.reset()` for reasy resetting before tests diff --git a/jest.config.js b/jest.config.js index f8e4972..9c19092 100644 --- a/jest.config.js +++ b/jest.config.js @@ -60,7 +60,11 @@ module.exports = { // globalTeardown: undefined, // A set of global variables that need to be available in all test environments - // globals: {}, + globals: { + 'ts-jest': { + diagnostics: false + } + }, // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. // maxWorkers: "50%", diff --git a/package-lock.json b/package-lock.json index 7e8ccbc..37e58b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "next-router-mock", - "version": "0.9.7", + "version": "0.9.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "next-router-mock", - "version": "0.9.7", + "version": "0.9.9", "license": "MIT", "devDependencies": { "@changesets/cli": "^2.26.2", @@ -14,7 +14,7 @@ "@types/jest": "^26.0.20", "doctoc": "^2.2.0", "jest": "^26.6.3", - "next": "^13.0.3", + "next": "^13.4.16", "prettier": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -1357,47 +1357,15 @@ } }, "node_modules/@next/env": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.3.tgz", - "integrity": "sha512-/4WzeG61Ot/PxsghXkSqQJ6UohFfwXoZ3dtsypmR9EBP+OIax9JRq0trq8Z/LCT9Aq4JbihVkaazRWguORjTAw==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.16.tgz", + "integrity": "sha512-pCU0sJBqdfKP9mwDadxvZd+eLz3fZrTlmmDHY12Hdpl3DD0vy8ou5HWKVfG0zZS6tqhL4wnQqRbspdY5nqa7MA==", "dev": true }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.3.tgz", - "integrity": "sha512-uxfUoj65CdFc1gX2q7GtBX3DhKv9Kn343LMqGNvXyuTpYTGMmIiVY7b9yF8oLWRV0gVKqhZBZifUmoPE8SJU6Q==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.0.3.tgz", - "integrity": "sha512-t2k+WDfg7Cq2z/EnalKGsd/9E5F4Hdo1xu+UzZXYDpKUI9zgE6Bz8ajQb8m8txv3qOaWdKuDa5j5ziq9Acd1Xw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.3.tgz", - "integrity": "sha512-wV6j6SZ1bc/YHOLCLk9JVqaZTCCey6HBV7inl2DriHsHqIcO6F3+QiYf0KXwRP9BE0GSZZrYd5mZQm2JPTHdJA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.16.tgz", + "integrity": "sha512-Rl6i1uUq0ciRa3VfEpw6GnWAJTSKo9oM2OrkGXPsm7rMxdd2FR5NkKc0C9xzFCI4+QtmBviWBdF2m3ur3Nqstw==", "cpu": [ "arm64" ], @@ -1411,9 +1379,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.3.tgz", - "integrity": "sha512-jaI2CMuYWvUtRixV3AIjUhnxUDU1FKOR+8hADMhYt3Yz+pCKuj4RZ0n0nY5qUf3qT1AtvnJXEgyatSFJhSp/wQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.16.tgz", + "integrity": "sha512-o1vIKYbZORyDmTrPV1hApt9NLyWrS5vr2p5hhLGpOnkBY1cz6DAXjv8Lgan8t6X87+83F0EUDlu7klN8ieZ06A==", "cpu": [ "x64" ], @@ -1426,42 +1394,10 @@ "node": ">= 10" } }, - "node_modules/@next/swc-freebsd-x64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.3.tgz", - "integrity": "sha512-nbyT0toBTJrcj5TCB9pVnQpGJ3utGyQj4CWegZs1ulaeUQ5Z7CS/qt8nRyYyOKYHtOdSCJ9Nw5F/RgKNkdpOdw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.3.tgz", - "integrity": "sha512-1naLxYvRUQCoFCU1nMkcQueRc0Iux9xBv1L5pzH2ejtIWFg8BrSgyuluJG4nyAhFCx4WG863IEIkAaefOowVdA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.3.tgz", - "integrity": "sha512-3Z4A8JkuGWpMVbUhUPQInK/SLY+kijTT78Q/NZCrhLlyvwrVxaQALJNlXzxDLraUgv4oVH0Wz/FIw1W9PUUhxA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.16.tgz", + "integrity": "sha512-JRyAl8lCfyTng4zoOmE6hNI2f1MFUr7JyTYCHl1RxX42H4a5LMwJhDVQ7a9tmDZ/yj+0hpBn+Aan+d6lA3v0UQ==", "cpu": [ "arm64" ], @@ -1475,9 +1411,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.3.tgz", - "integrity": "sha512-MoYe9SM40UaunTjC+01c9OILLH3uSoeri58kDMu3KF/EFEvn1LZ6ODeDj+SLGlAc95wn46hrRJS2BPmDDE+jFQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.16.tgz", + "integrity": "sha512-9gqVqNzUMWbUDgDiND18xoUqhwSm2gmksqXgCU0qaOKt6oAjWz8cWYjgpPVD0WICKFylEY/gvPEP1fMZDVFZ/g==", "cpu": [ "arm64" ], @@ -1491,9 +1427,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.3.tgz", - "integrity": "sha512-z22T5WGnRanjLMXdF0NaNjSpBlEzzY43t5Ysp3nW1oI6gOkub6WdQNZeHIY7A2JwkgSWZmtjLtf+Fzzz38LHeQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.16.tgz", + "integrity": "sha512-KcQGwchAKmZVPa8i5PLTxvTs1/rcFnSltfpTm803Tr/BtBV3AxCkHLfhtoyVtVzx/kl/oue8oS+DSmbepQKwhw==", "cpu": [ "x64" ], @@ -1507,9 +1443,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.3.tgz", - "integrity": "sha512-ZOMT7zjBFmkusAtr47k8xs/oTLsNlTH6xvYb+iux7yly2hZGwhfBLzPGBsbeMZukZ96IphJTagT+C033s6LNVA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.16.tgz", + "integrity": "sha512-2RbMZNxYnJmW8EPHVBsGZPq5zqWAyBOc/YFxq/jIQ/Yn3RMFZ1dZVCjtIcsiaKmgh7mjA/W0ApbumutHNxRqqQ==", "cpu": [ "x64" ], @@ -1523,9 +1459,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.3.tgz", - "integrity": "sha512-Q4BM16Djl+Oah9UdGrvjFYgoftYB2jNd+rtRGPX5Mmxo09Ry/KiLbOZnoUyoIxKc1xPyfqMXuaVsAFQLYs0KEQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.16.tgz", + "integrity": "sha512-thDcGonELN7edUKzjzlHrdoKkm7y8IAdItQpRvvMxNUXa4d9r0ElofhTZj5emR7AiXft17hpen+QAkcWpqG7Jg==", "cpu": [ "arm64" ], @@ -1539,9 +1475,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.3.tgz", - "integrity": "sha512-Sa8yGkNeRUsic8Qjf7MLIAfP0p0+einK/wIqJ8UO1y76j+8rRQu42AMs5H4Ax1fm9GEYq6I8njHtY59TVpTtGQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.16.tgz", + "integrity": "sha512-f7SE1Mo4JAchUWl0LQsbtySR9xCa+x55C0taetjUApKtcLR3AgAjASrrP+oE1inmLmw573qRnE1eZN8YJfEBQw==", "cpu": [ "ia32" ], @@ -1555,9 +1491,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.3.tgz", - "integrity": "sha512-IAptmSqA7k4tQzaw2NAkoEjj3+Dz9ceuvlEHwYh770MMDL4V0ku2m+UHrmn5HUCEDHhgwwjg2nyf6728q2jr1w==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.16.tgz", + "integrity": "sha512-WamDZm1M/OEM4QLce3lOmD1XdLEl37zYZwlmOLhmF7qYJ2G6oYm9+ejZVv+LakQIsIuXhSpVlOvrxIAHqwRkPQ==", "cpu": [ "x64" ], @@ -1624,9 +1560,9 @@ } }, "node_modules/@swc/helpers": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", - "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, "dependencies": { "tslib": "^2.4.0" @@ -2497,6 +2433,18 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -4131,6 +4079,12 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -6731,51 +6685,45 @@ "dev": true }, "node_modules/next": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.0.3.tgz", - "integrity": "sha512-rFQeepcenRxKzeKlh1CsmEnxsJwhIERtbUjmYnKZyDInZsU06lvaGw5DT44rlNp1Rv2MT/e9vffZ8vK+ytwXHA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.16.tgz", + "integrity": "sha512-1xaA/5DrfpPu0eV31Iro7JfPeqO8uxQWb1zYNTe+KDKdzqkAGapLcDYHMLNKXKB7lHjZ7LfKUOf9dyuzcibrhA==", "dev": true, "dependencies": { - "@next/env": "13.0.3", - "@swc/helpers": "0.4.11", + "@next/env": "13.4.16", + "@swc/helpers": "0.5.1", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", - "styled-jsx": "5.1.0", - "use-sync-external-store": "1.2.0" + "styled-jsx": "5.1.1", + "watchpack": "2.4.0", + "zod": "3.21.4" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=14.6.0" + "node": ">=16.8.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "13.0.3", - "@next/swc-android-arm64": "13.0.3", - "@next/swc-darwin-arm64": "13.0.3", - "@next/swc-darwin-x64": "13.0.3", - "@next/swc-freebsd-x64": "13.0.3", - "@next/swc-linux-arm-gnueabihf": "13.0.3", - "@next/swc-linux-arm64-gnu": "13.0.3", - "@next/swc-linux-arm64-musl": "13.0.3", - "@next/swc-linux-x64-gnu": "13.0.3", - "@next/swc-linux-x64-musl": "13.0.3", - "@next/swc-win32-arm64-msvc": "13.0.3", - "@next/swc-win32-ia32-msvc": "13.0.3", - "@next/swc-win32-x64-msvc": "13.0.3" + "@next/swc-darwin-arm64": "13.4.16", + "@next/swc-darwin-x64": "13.4.16", + "@next/swc-linux-arm64-gnu": "13.4.16", + "@next/swc-linux-arm64-musl": "13.4.16", + "@next/swc-linux-x64-gnu": "13.4.16", + "@next/swc-linux-x64-musl": "13.4.16", + "@next/swc-win32-arm64-msvc": "13.4.16", + "@next/swc-win32-ia32-msvc": "13.4.16", + "@next/swc-win32-x64-msvc": "13.4.16" }, "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", + "@opentelemetry/api": "^1.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { + "@opentelemetry/api": { "optional": true }, "sass": { @@ -8729,6 +8677,15 @@ "mixme": "^0.5.1" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string-length": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", @@ -8853,9 +8810,9 @@ } }, "node_modules/styled-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz", - "integrity": "sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "dev": true, "dependencies": { "client-only": "0.0.1" @@ -9142,9 +9099,9 @@ } }, "node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, "node_modules/tty-table": { @@ -9580,15 +9537,6 @@ "node": ">=0.10.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "dev": true, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -9729,6 +9677,19 @@ "makeerror": "1.0.x" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -9978,6 +9939,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", @@ -11171,99 +11141,71 @@ } }, "@next/env": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.3.tgz", - "integrity": "sha512-/4WzeG61Ot/PxsghXkSqQJ6UohFfwXoZ3dtsypmR9EBP+OIax9JRq0trq8Z/LCT9Aq4JbihVkaazRWguORjTAw==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.16.tgz", + "integrity": "sha512-pCU0sJBqdfKP9mwDadxvZd+eLz3fZrTlmmDHY12Hdpl3DD0vy8ou5HWKVfG0zZS6tqhL4wnQqRbspdY5nqa7MA==", "dev": true }, - "@next/swc-android-arm-eabi": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.0.3.tgz", - "integrity": "sha512-uxfUoj65CdFc1gX2q7GtBX3DhKv9Kn343LMqGNvXyuTpYTGMmIiVY7b9yF8oLWRV0gVKqhZBZifUmoPE8SJU6Q==", - "dev": true, - "optional": true - }, - "@next/swc-android-arm64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.0.3.tgz", - "integrity": "sha512-t2k+WDfg7Cq2z/EnalKGsd/9E5F4Hdo1xu+UzZXYDpKUI9zgE6Bz8ajQb8m8txv3qOaWdKuDa5j5ziq9Acd1Xw==", - "dev": true, - "optional": true - }, "@next/swc-darwin-arm64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.0.3.tgz", - "integrity": "sha512-wV6j6SZ1bc/YHOLCLk9JVqaZTCCey6HBV7inl2DriHsHqIcO6F3+QiYf0KXwRP9BE0GSZZrYd5mZQm2JPTHdJA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.16.tgz", + "integrity": "sha512-Rl6i1uUq0ciRa3VfEpw6GnWAJTSKo9oM2OrkGXPsm7rMxdd2FR5NkKc0C9xzFCI4+QtmBviWBdF2m3ur3Nqstw==", "dev": true, "optional": true }, "@next/swc-darwin-x64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.0.3.tgz", - "integrity": "sha512-jaI2CMuYWvUtRixV3AIjUhnxUDU1FKOR+8hADMhYt3Yz+pCKuj4RZ0n0nY5qUf3qT1AtvnJXEgyatSFJhSp/wQ==", - "dev": true, - "optional": true - }, - "@next/swc-freebsd-x64": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.0.3.tgz", - "integrity": "sha512-nbyT0toBTJrcj5TCB9pVnQpGJ3utGyQj4CWegZs1ulaeUQ5Z7CS/qt8nRyYyOKYHtOdSCJ9Nw5F/RgKNkdpOdw==", - "dev": true, - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.0.3.tgz", - "integrity": "sha512-1naLxYvRUQCoFCU1nMkcQueRc0Iux9xBv1L5pzH2ejtIWFg8BrSgyuluJG4nyAhFCx4WG863IEIkAaefOowVdA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.16.tgz", + "integrity": "sha512-o1vIKYbZORyDmTrPV1hApt9NLyWrS5vr2p5hhLGpOnkBY1cz6DAXjv8Lgan8t6X87+83F0EUDlu7klN8ieZ06A==", "dev": true, "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.0.3.tgz", - "integrity": "sha512-3Z4A8JkuGWpMVbUhUPQInK/SLY+kijTT78Q/NZCrhLlyvwrVxaQALJNlXzxDLraUgv4oVH0Wz/FIw1W9PUUhxA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.16.tgz", + "integrity": "sha512-JRyAl8lCfyTng4zoOmE6hNI2f1MFUr7JyTYCHl1RxX42H4a5LMwJhDVQ7a9tmDZ/yj+0hpBn+Aan+d6lA3v0UQ==", "dev": true, "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.0.3.tgz", - "integrity": "sha512-MoYe9SM40UaunTjC+01c9OILLH3uSoeri58kDMu3KF/EFEvn1LZ6ODeDj+SLGlAc95wn46hrRJS2BPmDDE+jFQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.16.tgz", + "integrity": "sha512-9gqVqNzUMWbUDgDiND18xoUqhwSm2gmksqXgCU0qaOKt6oAjWz8cWYjgpPVD0WICKFylEY/gvPEP1fMZDVFZ/g==", "dev": true, "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.0.3.tgz", - "integrity": "sha512-z22T5WGnRanjLMXdF0NaNjSpBlEzzY43t5Ysp3nW1oI6gOkub6WdQNZeHIY7A2JwkgSWZmtjLtf+Fzzz38LHeQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.16.tgz", + "integrity": "sha512-KcQGwchAKmZVPa8i5PLTxvTs1/rcFnSltfpTm803Tr/BtBV3AxCkHLfhtoyVtVzx/kl/oue8oS+DSmbepQKwhw==", "dev": true, "optional": true }, "@next/swc-linux-x64-musl": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.0.3.tgz", - "integrity": "sha512-ZOMT7zjBFmkusAtr47k8xs/oTLsNlTH6xvYb+iux7yly2hZGwhfBLzPGBsbeMZukZ96IphJTagT+C033s6LNVA==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.16.tgz", + "integrity": "sha512-2RbMZNxYnJmW8EPHVBsGZPq5zqWAyBOc/YFxq/jIQ/Yn3RMFZ1dZVCjtIcsiaKmgh7mjA/W0ApbumutHNxRqqQ==", "dev": true, "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.0.3.tgz", - "integrity": "sha512-Q4BM16Djl+Oah9UdGrvjFYgoftYB2jNd+rtRGPX5Mmxo09Ry/KiLbOZnoUyoIxKc1xPyfqMXuaVsAFQLYs0KEQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.16.tgz", + "integrity": "sha512-thDcGonELN7edUKzjzlHrdoKkm7y8IAdItQpRvvMxNUXa4d9r0ElofhTZj5emR7AiXft17hpen+QAkcWpqG7Jg==", "dev": true, "optional": true }, "@next/swc-win32-ia32-msvc": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.0.3.tgz", - "integrity": "sha512-Sa8yGkNeRUsic8Qjf7MLIAfP0p0+einK/wIqJ8UO1y76j+8rRQu42AMs5H4Ax1fm9GEYq6I8njHtY59TVpTtGQ==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.16.tgz", + "integrity": "sha512-f7SE1Mo4JAchUWl0LQsbtySR9xCa+x55C0taetjUApKtcLR3AgAjASrrP+oE1inmLmw573qRnE1eZN8YJfEBQw==", "dev": true, "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.0.3.tgz", - "integrity": "sha512-IAptmSqA7k4tQzaw2NAkoEjj3+Dz9ceuvlEHwYh770MMDL4V0ku2m+UHrmn5HUCEDHhgwwjg2nyf6728q2jr1w==", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.16.tgz", + "integrity": "sha512-WamDZm1M/OEM4QLce3lOmD1XdLEl37zYZwlmOLhmF7qYJ2G6oYm9+ejZVv+LakQIsIuXhSpVlOvrxIAHqwRkPQ==", "dev": true, "optional": true }, @@ -11312,9 +11254,9 @@ } }, "@swc/helpers": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", - "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, "requires": { "tslib": "^2.4.0" @@ -12046,6 +11988,15 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -13331,6 +13282,12 @@ "is-glob": "^4.0.1" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -15306,30 +15263,28 @@ "dev": true }, "next": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.0.3.tgz", - "integrity": "sha512-rFQeepcenRxKzeKlh1CsmEnxsJwhIERtbUjmYnKZyDInZsU06lvaGw5DT44rlNp1Rv2MT/e9vffZ8vK+ytwXHA==", - "dev": true, - "requires": { - "@next/env": "13.0.3", - "@next/swc-android-arm-eabi": "13.0.3", - "@next/swc-android-arm64": "13.0.3", - "@next/swc-darwin-arm64": "13.0.3", - "@next/swc-darwin-x64": "13.0.3", - "@next/swc-freebsd-x64": "13.0.3", - "@next/swc-linux-arm-gnueabihf": "13.0.3", - "@next/swc-linux-arm64-gnu": "13.0.3", - "@next/swc-linux-arm64-musl": "13.0.3", - "@next/swc-linux-x64-gnu": "13.0.3", - "@next/swc-linux-x64-musl": "13.0.3", - "@next/swc-win32-arm64-msvc": "13.0.3", - "@next/swc-win32-ia32-msvc": "13.0.3", - "@next/swc-win32-x64-msvc": "13.0.3", - "@swc/helpers": "0.4.11", + "version": "13.4.16", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.16.tgz", + "integrity": "sha512-1xaA/5DrfpPu0eV31Iro7JfPeqO8uxQWb1zYNTe+KDKdzqkAGapLcDYHMLNKXKB7lHjZ7LfKUOf9dyuzcibrhA==", + "dev": true, + "requires": { + "@next/env": "13.4.16", + "@next/swc-darwin-arm64": "13.4.16", + "@next/swc-darwin-x64": "13.4.16", + "@next/swc-linux-arm64-gnu": "13.4.16", + "@next/swc-linux-arm64-musl": "13.4.16", + "@next/swc-linux-x64-gnu": "13.4.16", + "@next/swc-linux-x64-musl": "13.4.16", + "@next/swc-win32-arm64-msvc": "13.4.16", + "@next/swc-win32-ia32-msvc": "13.4.16", + "@next/swc-win32-x64-msvc": "13.4.16", + "@swc/helpers": "0.5.1", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", - "styled-jsx": "5.1.0", - "use-sync-external-store": "1.2.0" + "styled-jsx": "5.1.1", + "watchpack": "2.4.0", + "zod": "3.21.4" } }, "nice-try": { @@ -16860,6 +16815,12 @@ "mixme": "^0.5.1" } }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, "string-length": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", @@ -16951,9 +16912,9 @@ } }, "styled-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz", - "integrity": "sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "dev": true, "requires": { "client-only": "0.0.1" @@ -17160,9 +17121,9 @@ } }, "tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, "tty-table": { @@ -17485,13 +17446,6 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "dev": true, - "requires": {} - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -17596,6 +17550,16 @@ "makeerror": "1.0.x" } }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -17800,6 +17764,12 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true }, + "zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "dev": true + }, "zwitch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", diff --git a/package.json b/package.json index 8092d3f..55a9f14 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@types/jest": "^26.0.20", "doctoc": "^2.2.0", "jest": "^26.6.3", - "next": "^13.0.3", + "next": "^13.4.16", "prettier": "^2.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/MemoryRouter.test.tsx b/src/MemoryRouter.test.tsx index fbe16ba..818270b 100644 --- a/src/MemoryRouter.test.tsx +++ b/src/MemoryRouter.test.tsx @@ -535,13 +535,6 @@ describe("MemoryRouter", () => { hash: "#hash", }); }); - - it('the "registerPaths" method is deprecated', async () => { - expect(() => { - // @ts-expect-error This should have type errors and runtime errors: - memoryRouter.registerPaths(["path"]); - }).toThrow("See the README for more details on upgrading."); - }); }); }); }); diff --git a/src/MemoryRouter.tsx b/src/MemoryRouter.tsx index 26127dc..97773ea 100644 --- a/src/MemoryRouter.tsx +++ b/src/MemoryRouter.tsx @@ -106,20 +106,25 @@ export class MemoryRouter extends BaseRouter { public async = false; /** - * This method was removed in v0.7.0. - * It has been replaced with "mockRouter.useParser(createDynamicRouteParser(...))" - * See the README for more details on upgrading. - * @deprecated + * Store extra metadata, needed to support App Router (next/navigation) */ - registerPaths: { ["This method has been replaced"]: "See the README for more details on upgrading" } = (() => { - throw new Error(` - This method was removed in v0.7.0. - It has been replaced with "mockRouter.useParser(createDynamicRouteParser(...))" - See the README for more details on upgrading. - `); - }) as any; - - useParser(parser: (urlObject: UrlObjectComplete) => void) { + public internal = { + query: {} as NextRouter["query"], + routeParams: {} as NextRouter["query"], + selectedLayoutSegment: "[next-router-mock] Not Yet Implemented", + selectedLayoutSegments: ["[next-router-mock] Not Yet Implemented"], + }; + + /** + * Removes all event handlers, and sets the current URL back to default. + * This will clear dynamic parsers, too. + */ + public reset() { + this.events = mitt(); + this.setCurrentUrl("/"); + } + + public useParser(parser: (urlObject: UrlObjectComplete) => void) { this.events.on("NEXT_ROUTER_MOCK:parse", parser); return () => this.events.off("NEXT_ROUTER_MOCK:parse", parser); } @@ -184,6 +189,8 @@ export class MemoryRouter extends BaseRouter { this.pathname = newRoute.pathname; this.query = { ...newRoute.query, ...newRoute.routeParams }; this.hash = newRoute.hash; + this.internal.query = newRoute.query; + this.internal.routeParams = newRoute.routeParams; if (options?.locale) { this.locale = options.locale; diff --git a/src/index.test.tsx b/src/index.test.tsx index 4628458..c0a5893 100644 --- a/src/index.test.tsx +++ b/src/index.test.tsx @@ -13,6 +13,7 @@ describe("next-overridable-hook", () => { expect(router).toEqual({ // Ignore these: events: expect.any(Object), + internal: expect.any(Object), async: expect.any(Boolean), push: expect.any(Function), replace: expect.any(Function), diff --git a/src/navigation/index.test.tsx b/src/navigation/index.test.tsx new file mode 100644 index 0000000..745dc39 --- /dev/null +++ b/src/navigation/index.test.tsx @@ -0,0 +1,128 @@ +import { act, renderHook, RenderHookResult } from "@testing-library/react"; +import singletonRouter from "../index"; +import { + useRouter, + useParams, + usePathname, + useSearchParams, + useSelectedLayoutSegment, + useSelectedLayoutSegments, +} from "./index"; +import { createDynamicRouteParser } from "../dynamic-routes"; + +describe("next/navigation", () => { + beforeEach(() => { + singletonRouter.reset(); + }); + + describe("useRouter", () => { + const hook = beforeEachRenderHook(() => useRouter()); + + it("should be a snapshot of the router", () => { + expect(hook.result.current).not.toBe(singletonRouter); + expect(hook.result.current.push).toBe(singletonRouter.push); + expect(hook.result.current.replace).toBe(singletonRouter.replace); + expect(Object.keys(hook.result.current)).toEqual([ + // + "push", + "replace", + "refresh", + "prefetch", + "back", + "forward", + ]); + }); + it("returns the same object after rerendering", () => { + const initial = hook.result.current; + hook.rerender(); + expect(hook.result.current).toBe(initial); + }); + it("pushing a route does not trigger a rerender", () => { + const initial = hook.result.current; + act(() => { + initial.push("/url"); + }); + expect(hook.result.current).toBe(initial); + }); + }); + + describe("usePathname", () => { + const hook = beforeEachRenderHook(() => usePathname()); + it("should return the current pathname", () => { + expect(hook.result.current).toEqual("/"); + }); + it("should update when a new path is pushed", () => { + act(() => { + singletonRouter.push("/new-path"); + }); + + expect(hook.result.current).toEqual("/new-path"); + }); + }); + + describe("useParams", () => { + beforeEach(() => { + singletonRouter.useParser(createDynamicRouteParser(["/[one]/[two]"])); + }); + const hook = beforeEachRenderHook(() => useParams()); + it("should contain the route params", () => { + expect(hook.result.current).toEqual({}); + + act(() => { + singletonRouter.push("/A/B"); + }); + + expect(hook.result.current).toEqual({ one: "A", two: "B" }); + }); + + it("should not contain search params", () => { + expect(hook.result.current).toEqual({}); + + act(() => { + singletonRouter.push("/A/B?one=ONE&two=TWO&three=THREE"); + }); + + expect(hook.result.current).toEqual({ one: "A", two: "B" }); + }); + }); + + describe("useSearchParams", () => { + const hook = beforeEachRenderHook(() => useSearchParams()); + it("should contain the search params", () => { + expect([...hook.result.current.entries()]).toEqual([]); + + act(() => { + singletonRouter.push("/path?one=1&two=2&three=3"); + }); + + expect([...hook.result.current.entries()]).toEqual([ + ["one", "1"], + ["two", "2"], + ["three", "3"], + ]); + }); + }); + + describe("useSelectedLayoutSegment", () => { + const hook = beforeEachRenderHook(() => useSelectedLayoutSegment()); + it("", () => { + // + }); + }); + + describe("useSelectedLayoutSegments", () => { + const hook = beforeEachRenderHook(() => useSelectedLayoutSegments()); + it(" ", () => { + // + }); + }); +}); + +function beforeEachRenderHook(render: () => T): RenderHookResult { + const hookResult = {} as any; + beforeEach(() => { + const newHookResult = renderHook(render); + Object.assign(hookResult, newHookResult); + }); + return hookResult; +} diff --git a/src/navigation/index.tsx b/src/navigation/index.tsx new file mode 100644 index 0000000..44334e4 --- /dev/null +++ b/src/navigation/index.tsx @@ -0,0 +1,82 @@ +import { useState, useEffect, useMemo } from "react"; +import { MemoryRouter } from "../MemoryRouter"; +import singletonRouter from "../index"; +import type * as NextNav from "next/navigation"; + +function useSnapshot(makeSnapshot: (r: MemoryRouter, prev: T | null) => T): T { + const [snapshot, setSnapshot] = useState(() => makeSnapshot(singletonRouter, null)); + + useEffect(() => { + // To ensure we don't call setRouter after unmounting: + let isMounted = true; + + const handleRouteChange = () => { + if (!isMounted) return; + + // Ensure the reference changes each render: + setSnapshot((prev) => makeSnapshot(singletonRouter, prev)); + }; + + singletonRouter.events.on("routeChangeComplete", handleRouteChange); + singletonRouter.events.on("hashChangeComplete", handleRouteChange); + return () => { + isMounted = false; + singletonRouter.events.off("routeChangeComplete", handleRouteChange); + singletonRouter.events.off("hashChangeComplete", handleRouteChange); + }; + }, []); + + return snapshot; +} + +export const useRouter: typeof NextNav.useRouter = () => { + // All these methods are static, and never trigger a rerender: + return useMemo( + () => ({ + push: (url, options) => singletonRouter.push(url), + replace: (url, options) => singletonRouter.replace(url), + refresh: singletonRouter.reload, + prefetch: singletonRouter.prefetch, + back: singletonRouter.back, + forward: singletonRouter.forward, + }), + [] + ); +}; + +export const useSearchParams: typeof NextNav.useSearchParams = () => { + return useSnapshot((r, prev) => { + const query = r.internal.query; + debugger; + // Build the search params from the query object: + const newSearchParams = new URLSearchParams(); + Object.keys(query).forEach((key) => { + const value = query[key]; + if (Array.isArray(value)) { + value.forEach((val) => newSearchParams.append(key, val)); + } else if (value !== undefined) { + newSearchParams.append(key, value); + } + }); + + // Prevent rerendering if the query is the same: + if (prev && newSearchParams.toString() === prev.toString()) { + return prev; + } + return newSearchParams as NextNav.ReadonlyURLSearchParams; + }); +}; + +export const usePathname: typeof NextNav.usePathname = () => { + return useSnapshot((r) => r.pathname); +}; + +export const useParams: typeof NextNav.useParams = () => { + type Params = ReturnType; + return useSnapshot((r) => r.internal.routeParams as Params); +}; + +export const useSelectedLayoutSegment: typeof NextNav.useSelectedLayoutSegment = () => + useSnapshot((r) => r.internal.selectedLayoutSegment); +export const useSelectedLayoutSegments: typeof NextNav.useSelectedLayoutSegments = () => + useSnapshot((r) => r.internal.selectedLayoutSegments);