Files
next.js/test/e2e/middleware-dynamic-basepath-matcher-rewrites/middleware-dynamic-basepath-matcher-rewrites.test.ts
Hendrik LiebauandGitHub f8499307ed Fix catch-all router.query corruption with basePath + rewrites (#93294)
In a Pages Router app that combines a `basePath`, `next.config.js`
`rewrites`, middleware, and a catch-all dynamic route, a client-side
`Link` navigation could land on the page with a corrupted
`router.query`. Instead of holding the captured route segments, the
catch-all param ended up holding the segments of the internal
`_next/data/<buildId>/...` URL. Page code that builds further URLs from
`router.query` then produced malformed paths and 404s in production.

The corruption originated in `getMiddlewareData`, which was passing
`nextConfig: undefined` to `getNextPathnameInfo` whenever
`__NEXT_HAS_REWRITES` was true. With basePath set, that meant the
basePath prefix was never stripped from the data-source URL, so the
`/_next/data/` check never matched and the data prefix was left intact.
The resulting pathname flowed back into `routeInfo.resolvedAs`, and on
catch-all routes the route regex matched it and overwrote
`router.query.<param>` with the data-URL segments.

The original ternary at this call site (added in #48753) was there to
avoid stripping the locale prefix, since `resolveRewrites` needs `as` to
keep its locale prefix to match locale-aware rewrite sources. Disabling
all of `nextConfig` was too coarse and broke basePath stripping in the
process. The fix passes a partial config with only `basePath` and
`trailingSlash`, which keeps the locale prefix intact while still
letting `getNextPathnameInfo` strip basePath before the data-prefix
check.

The new `test/e2e/middleware-dynamic-basepath-matcher-rewrites/` fixture
is the catch-all + basePath + rewrites + middleware variant of
`test/e2e/middleware-dynamic-basepath-matcher/` (#48753's regression
test), and asserts that `router.query.path` is preserved across a
client-side `Link` navigation.
2026-05-13 14:50:03 +02:00

20 lines
607 B
TypeScript

import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
describe('middleware-dynamic-basepath-matcher-rewrites', () => {
const { next } = nextTestSetup({
files: __dirname,
})
it('preserves router.query on client-side navigation to a catch-all page', async () => {
const browser = await next.browser('/docs')
await browser.elementById('catchall-link').click()
await retry(async () => {
expect(await browser.elementById('page-title').text()).toBe('CatchAll')
})
expect(await browser.elementById('query-path').text()).toBe('["first"]')
})
})