next.js/test/e2e/app-dir/concurrent-navigations/mismatching-prefetch.test.ts
mismatching-prefetch.test.ts81 lines2.8 KB
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'
      )
    }
  )
})
Quest for Codev2.0.0
/
SIGN IN