Files
next.js/test/e2e/app-dir/interception-route-prefetch-cache/interception-route-prefetch-cache.test.ts
Zack TannerandGitHub 1337c7a3e5 fix dynamic param extraction for interception routes (#67400)
### What
When using `generateStaticParams` with interception routes, the
interception would never occur, and instead an MPA navigation would take
place to the targeted link.

### Why
For interception rewrites, we use a `__NEXT_EMPTY_PARAM__` marker (in
place of the actual param slot, eg `:locale`) for any params that are
discovered prior to the interception marker. This is because during
route resolution, the `params` for the interception route might not
contain the same `params` for the page that triggered the interception.
The dynamic params are then extracted from `FlightRouterState` at render
time. However, when `generateStaticParams` is present, the
`FlightRouterState` header is stripped from the request, so it isn't
able to extract the dynamic params and so the router thinks the new tree
is a new root layout, hence the MPA navigation.

### How
This removes the `__NEXT_EMPTY_PARAM__` hack and several spots where we
were forcing interception routes to be dynamic as a workaround to the
above bug. Now when resolving the route, if the request was to an
interception route, we extract the dynamic params from the request
before constructing the final rewritten URL. This will ensure that the
params from the "current" route are available in addition to the params
from the interception route without needing to defer until render.

Fixes #65192
Fixes #52880
2024-07-03 11:21:07 -07:00

73 lines
2.3 KiB
TypeScript

import { nextTestSetup, FileRef } from 'e2e-utils'
import { retry } from 'next-test-utils'
import { join } from 'path'
describe('interception-route-prefetch-cache', () => {
function runTests({ next }: ReturnType<typeof nextTestSetup>) {
it('should render the correct interception when two distinct layouts share the same path structure', async () => {
const browser = await next.browser('/')
await browser.waitForIdleNetwork()
await browser.elementByCss('[href="/foo"]').click()
await retry(async () => {
expect(await browser.elementById('children').text()).toMatch(/Foo Page/)
})
await browser.elementByCss('[href="/post/1"]').click()
await retry(async () => {
// Ensure the existing page content is still the same
expect(await browser.elementById('children').text()).toMatch(/Foo Page/)
// Verify we got the right interception
expect(await browser.elementById('slot').text()).toMatch(
/Intercepted on Foo Page/
)
})
// Go back home. At this point, the router cache should have content from /foo
// Now we want to ensure that /bar doesn't share that same prefetch cache entry
await browser.elementByCss('[href="/"]').click()
await browser.waitForElementByCss('#home')
await browser.elementByCss('[href="/bar"]').click()
await retry(async () => {
expect(await browser.elementById('children').text()).toMatch(/Bar Page/)
})
await browser.elementByCss('[href="/post/1"]').click()
// Ensure the existing page content is still the same. If the prefetch cache resolved the wrong cache node
// then we'd see the content from /foo
await retry(async () => {
expect(await browser.elementById('children').text()).toMatch(/Bar Page/)
expect(await browser.elementById('slot').text()).toMatch(
/Intercepted on Bar Page/
)
})
})
}
describe('runtime = nodejs', () => {
runTests(
nextTestSetup({
files: __dirname,
})
)
})
describe('runtime = edge', () => {
runTests(
nextTestSetup({
files: {
app: new FileRef(join(__dirname, 'app')),
'app/layout.tsx': new FileRef(join(__dirname, 'app/layout-edge.tsx')),
},
})
)
})
})