Files
next.js/test/e2e/app-dir/dynamic-interception-route-revalidate/dynamic-interception-route-revalidate.test.ts
Zack TannerandGitHub d2548b5435 fix router revalidation behavior for dynamic interception routes (#63768)
### What
When calling `revalidatePath` or `revalidateTag` in a server action for
an intercepted route with dynamic segments, the page would do a full
browser refresh.

### Why
When constructing rewrites for interception routes, the route params
leading up to the interception route are "voided" with a
`__NEXT_EMPTY_PARAM__` demarcation. When it comes time to look up the
values for these dynamic segments, since the params aren't going to be
part of the URL, they get matched via `FlightRouterState`
([ref](https://github.com/vercel/next.js/blob/d67d658ce7396c4b6be1b724be5f45763d5a1803/packages/next/src/server/app-render/app-render.tsx#L153-L201)).

The `shouldProvideFlightRouterState` variable only passes it through for
RSC requests; however, since the server action will perform the action &
return the flight data in a single pass, that means the updated tree
from the server action isn't going to receive the `FlightRouterState`
when constructing the new tree. This means the old tree will have a
`["locale", "en", "d"]` segment, and the new tree from the server action
will have `"[locale]"`. When the router detects this kind of segment
mismatch, it assumes the user navigated to a new root layout, and
triggers an MPA navigation.

### How
This unconditionally provides the `FlightRouterState` to
`makeGetDynamicParamFromSegment` so that it can properly extract dynamic
params for interception routes. We currently enforce interception routes
to be dynamic due to this `FlightRouterState` dependency.

Fixes #59796
Closes NEXT-2079
2024-03-28 13:35:22 +00:00

46 lines
1.4 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
describe('dynamic-interception-route-revalidate', () => {
const { next } = nextTestSetup({
files: __dirname,
})
it('should refresh the dynamic intercepted route when the interception route is revalidated', async () => {
const browser = await next.browser('/en')
// trigger the interception
await browser.elementByCss("[href='/en/photos/1/view']").click()
// verify we're on the intercepted page
await browser.waitForElementByCss('#intercepted-page')
expect(await browser.elementByCss('h2').text()).toBe('Photo Id: 1')
// trigger the revalidate
await browser.elementByCss('button').click()
// make sure the loading state fired
await browser.waitForElementByCss('#loading')
// verify that we get a result from the server action
await retry(async () => {
const result = await browser.elementByCss('#result').text()
expect(result).toMatch(/^Result: 0(\.\d+)?$/)
})
// make sure we're still on the intercepted page
expect(await browser.hasElementByCssSelector('#intercepted-page')).toBe(
true
)
// refresh the page to get the full (non-intercepted) page
await browser.refresh()
expect(await browser.hasElementByCssSelector('#intercepted-page')).toBe(
false
)
expect(await browser.hasElementByCssSelector('#full-page')).toBe(true)
})
})