import { nextTestSetup } from 'e2e-utils' import type * as Playwright from 'playwright' import { createRouterAct } from 'router-act' describe('mismatching prefetch', () => { const { next, isNextDev } = nextTestSetup({ files: __dirname, }) if (isNextDev) { test('disabled in development', () => {}) return } function relativeHref(href: string) { const url = new URL(href) return url.pathname + url.search + url.hash } it( 'recovers when a navigation rewrites to a different route than the one ' + 'that was prefetched', async () => { let page: Playwright.Page const browser = await next.browser('/mismatching-prefetch', { beforePageLoad(p: Playwright.Page) { page = p }, }) const act = createRouterAct(page) // Reveal the link to trigger a prefetch of page A. const toggle = await browser.elementByCss( 'input[data-link-accordion="/mismatching-prefetch/dynamic-page/a?mismatch-rewrite=./b"]' ) await act(async () => await toggle.click(), { includes: 'Loading a...', }) // When we click the link to navigate, the navigation will rewrite to // a different route than the one that was prefetched. await act( async () => { const link = await browser.elementByCss( 'a[href="/mismatching-prefetch/dynamic-page/a?mismatch-rewrite=./b"]' ) await link.click() // Immeidately after the click, the app navigates to the loading state // that was prefetched, which is for page A. const pageALoading = await browser.elementById( 'dynamic-page-loading-a' ) expect(relativeHref(await browser.url())).toBe( '/mismatching-prefetch/dynamic-page/a?mismatch-rewrite=./b' ) expect(await pageALoading.text()).toBe('Loading a...') // Simultaneously, the dynamic content for page A is requested. }, // When the dynamic request is received, Next.js will discover that the // route has changed and rewrite to page B. The client will detect a // mismatch and render again using the new route from the server. // // This shouldn't require a second dynamic request, though, because we // can reuse the data sent by the server. So, page B should only render // once on the server. [{ includes: 'Dynamic page b' }] ) // The redirected page loads successfully. const pageBContent = await browser.elementById('dynamic-page-content-b') expect(await pageBContent.text()).toBe('Dynamic page b') // The browser's URL hasn't changed, because this was a rewrite, not // a redirect. expect(relativeHref(await browser.url())).toBe( '/mismatching-prefetch/dynamic-page/a?mismatch-rewrite=./b' ) } ) })