mport { nextTestSetup } from 'e2e-utils'
import { waitForNoRedbox } from 'next-test-utils'

describe('global-not-found - no-root-layout', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  it('should render global-not-found for 404', async () => {
    const browser = await next.browser('/does-not-exist')
    if (isNextDev) {
      await waitForNoRedbox(browser)
    }

    const errorTitle = await browser.elementByCss('#global-error-title').text()
    expect(errorTitle).toBe(

sync () => {
    const $ = await next.render$('/does-not-exist')
    const errorTitle = $('#global-error-title').text()
    expect(errorTitle).toBe('global-not-found')
    const notFoundHtmlProp = $('html').attr('data-global-not-found')
    expect(notFound

'global-not-found')
    const notFoundHtmlProp = await browser
      .elementByCss('html')
      .getAttribute('data-global-not-found')
    expect(notFoundHtmlProp).toBe('true')
  })

  it('should ssr global-not-found for 404', a


mport { nextTestSetup } from 'e2e-utils'

describe('global-not-found - both-present', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should render global-not-found for 404 routes', async () => {
    const $ = await next.render$('/does-not-exist')
    expect($('html').attr('data-global-not-found')).toBe('true')
    expect($('#global-error-title').text()).toBe('global-not-found')

    const browser = await next.browser('/does-not-exist')
    expect(await browser.elementByCss('#gl

ng notFound() in a page', async () => {
    const browser = await next.browser('/call-not-found')
    expect(await browser.elementByCss('#not-found-boundary').text()).toBe(
      'not-found.js'
    )
    expect(
      await browser.elementByCss('html').get

obal-error-title').text()).toBe(
      'global-not-found'
    )
    expect(
      await browser.elementByCss('html').getAttribute('data-global-not-found')
    ).toBe('true')
  })

  it('should render not-found boundary when calli


 { nextTestSetup } from 'e2e-utils'

describe(`mdx`, () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      '@next/mdx': 'canary',
      '@mdx-js/loader': '^2.2.1',
    },
  })

  describe('app directory', () => {
    it('should work in initial html', async () => {
      const $ = await next.render$('/')
      expect($('h1').text()).toBe('Hello World')
      expect($('p').text()).toBe('This is MDX!')
    })

    it('should work using browser', async () => {
      const br

ponents', async () => {
      const $ = await next.render$('/')
      expect($('h2').text()).toBe('This is a client component')
    })
  })

  describe('pages directory', () => {
    it('should work in initial html', async () => {
      const $ = await nex

owser = await next.browser('/')
      expect(await browser.elementByCss('h1').text()).toBe('Hello World')
      expect(await browser.elementByCss('p').text()).toBe('This is MDX!')
    })

    it('should allow importing client com


import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'

describe('global-not-found - cache-components', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should render global-not-found for 404 routes', async () => {
    await next.fetch('/does-not-exist')
    expect(next.cliOutput).not.toContain(
      'did not produce a static shell and Next.js was unable to determine a reason. This is a bug in Next.js'
    )
  })

  it('should render not-found boundary

 => {
      expect(await browser.elementByCss('h1').text()).toBe('Global Not Found')
    })
    expect(next.cliOutput).not.toContain(
      'did not produce a static shell and Next.js was unable to determine a reason. This is a bug in Next.js'
    )
  })
}

 when calling notFound() in a page', async () => {
    const browser = await next.browser('/action')
    // submit form with #not-found-btn button
    await browser.elementByCss('#not-found-btn').click()

    await retry(async ()


 to work locally you need to use `pnpm next-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-external-esm-package/exports'
import * as ExportsNamed from 'my-external-esm-package/exports'
import { named as namedExports } from 'my-external-esm-package/exports'

import ImportsDefault from 'my-external-esm-package/imports'
import * as ImportsNamed from 'my-external-esm-package/import

external-esm-package/imports').then(
  (mod) => JSON.stringify(mod)
)

export default function Client() {
  return (

Client

Exports

Static

          D

s'
import { named as namedImports } from 'my-external-esm-package/imports'

const pendingDynamicExports = import('my-external-esm-package/exports').then(
  (mod) => JSON.stringify(mod)
)

const pendingDynamicImports = import('my-


ext-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-external-esm-package/exports'
import * as ExportsNamed from 'my-external-esm-package/exports'
import { named as namedExports } from 'my-external-esm-package/exports'

import ImportsDefault from 'my-external-esm-package/imports'
import * as ImportsNamed from 'my-external-esm-package/imports'
import { named as namedImports } from

mod) => JSON.stringify(mod)
)

import Client from './client'

export default function Page() {
  return (
    <>

Server

Exports

Static

 'my-external-esm-package/imports'

const pendingDynamicExports = import('my-external-esm-package/exports').then(
  (mod) => JSON.stringify(mod)
)

const pendingDynamicImports = import('my-external-esm-package/imports').then(
  (


ly you need to use `pnpm next-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-cjs-package/exports'
import * as ExportsNamed from 'my-cjs-package/exports'
import { named as namedExports } from 'my-cjs-package/exports'

import ImportsDefault from 'my-cjs-package/imports'
import * as ImportsNamed from 'my-cjs-package/imports'
import { named as namedImports } from 'my-cjs-package/im

m './client'

export default function Page() {
  return (
    <>

Server

Exports

Static

            Default:

{JSON

ports'

const pendingDynamicExports = import('my-cjs-package/exports').then((mod) =>
  JSON.stringify(mod)
)

const pendingDynamicImports = import('my-cjs-package/imports').then((mod) =>
  JSON.stringify(mod)
)

import Client fro


 to work locally you need to use `pnpm next-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-external-cjs-package/exports'
import * as ExportsNamed from 'my-external-cjs-package/exports'
import { named as namedExports } from 'my-external-cjs-package/exports'

import ImportsDefault from 'my-external-cjs-package/imports'
import * as ImportsNamed from 'my-external-cjs-package/import

external-cjs-package/imports').then(
  (mod) => JSON.stringify(mod)
)

export default function Client() {
  return (

Client

Exports

Static

          D

s'
import { named as namedImports } from 'my-external-cjs-package/imports'

const pendingDynamicExports = import('my-external-cjs-package/exports').then(
  (mod) => JSON.stringify(mod)
)

const pendingDynamicImports = import('my-


etup({
    files: __dirname,
  })

  async function setup(initialPath: string) {
    let page: Playwright.Page
    const browser = await next.browser(initialPath, {
      beforePageLoad(p: Playwright.Page) {
        page = p
      },
    })
    const act = createRouterAct(page!)
    return { browser, act }
  }

  it('preserves leaf form state on browser back navigation', async () => {
    const { browser, act } = await setup('/x/1')
    await browser.elementByCss('[data-testid="leaf-input"]').type('hello')

ntByCss('[data-testid="pathname"]').text()).toBe(
      '/x/1'
    )
    expect(
      await browser.elementByCss('[data-testid="leaf-input"]').getValue()
    ).toBe('hello')
  })

  it('resets leaf form state when re-entering a route via fresh push', asyn

    await act(async () => {
      await browser.elementByCss('input[data-link-accordion="/x/2"]').click()
      await browser.elementByCss('a[href="/x/2"]').click()
    })

    await browser.back()
    expect(await browser.eleme


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 brow

 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

ser.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


describe('PPR - partial hydration', () => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    // the file-patching strategy we use for synchronizing the test doesn't work
    // on deployments
    skipDeployment: true,
  })

  if (isNextDev || skipped) {
    it.skip('only testable in production (non-deployment)', () => {})
    return
  }

  describe.each([
    {
      description: 'Static shell, no streaming metadata',
      path: '/with-shell/without-metadata',
    },
    {

ompleteness.
      description: 'Static shell, streaming metadata',
      path: '/with-shell/with-streaming-metadata',
    },
    {
      description: 'No static shell, no streaming metadata',
      path: '/without-shell/without-metadata',
    },
    {

      // Streaming metadata shouldn't affect streaming order, because if we have a static shell,
      // then RSC scripts (and thus hydration) don't need to wait for any HTML to be rendered.
      // I'm including it here for c


mport { Suspense } from 'react'
import { connection } from 'next/server'
import { HydrationIndicator } from '../../hydration-indicator'
import waitForMarkerFile from '../../../waitForMarkerFile'
import type { Metadata } from 'next'

export async function generateMetadata(): Promise<Metadata> {
  await connection()
  return {
    title: 'Resume test',
  }
}

export default function Page() {
  return (

This is a page with static shell + streaming metadata

  )
}

async function SlowServerComponent() {
  await connection()
  await waitForMarkerFile()
  const randomValue = Math.floor(Math.random() * 1000)
  return (

{`Random value: ${randomValue}`}

      <Hy

Static shell

        <HydrationIndicator id="shell-hydrated" />

        <Suspense fallback={
Loading...
}>
          <SlowServerComponent />
        </Suspense>


'next/link'

export default async function Page(props: PageProps<'/loading-scroll'>) {
  const search = await props.searchParams
  const skipSleep = !!search.skipSleep
  if (!skipSleep) {
    await new Promise((resolve) => setTimeout(resolve, 5000))
  }
  return (
    <>
      {search.page ?
{search.page}
 : null}

Content that is hidden.

Content which is not hidden.

      {
        // Repea

t 500 elements
        Array.from({ length: 500 }, (


tTestSetup } from 'e2e-utils'

const describeHeaded = process.env.HEADLESS ? describe.skip : describe

describeHeaded('fetch-abort-on-refresh', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not show abort error in global error boundary when restoring from bfcache', async () => {
    // This test ensures that when restoring a page from the browser bfcache that was pending RSC data,
    // that the abort does not propagate to a user's error boundary.
    const browser = a

ical waitUntil: 'load' option here as the event is never being triggered if we hit the bfcache
    await browser.back({ waitUntil: 'commit' })

    // Check that we're back on the slow page (the page that was first redirected to, before the MPA, not the er

wait next.browser('/', { headless: false })

    await browser.elementById('trigger-navigation').click()

    await browser.waitForElementByCss('#root-2')

    // Go back to trigger bfcache restoration
    // we overwrite the typ


 { nextTestSetup } from 'e2e-utils'

describe('global-not-found - metadata', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should render metadata of global-not-found for 404', async () => {
    // assert SSR metadata
    const $ = await next.render$('/does-not-exist')
    expect($('title').text()).toBe('global-not-found')
    expect($('meta[name="description"]').attr('content')).toBe(
      'global-not-found description'
    )
    // pick up static icon svg
    expect($('link[

ser.elementByCss('meta[name="description"]')
    expect(await title.text()).toBe('global-not-found')
    expect(await description.getAttribute('content')).toBe(
      'global-not-found description'
    )
    // pick up static icon svg
    const icon = awai

rel="icon"]').attr('type')).toBe('image/svg+xml')

    // assert hydrated metadata
    const browser = await next.browser('/does-not-exist')
    const title = await browser.elementByCss('title')
    const description = await brow


from 'e2e-utils'

describe('edge runtime node compatibility', () => {
  const { next, isNextStart } = nextTestSetup({
    files: __dirname,
  })

  it('[app] supports node:buffer', async () => {
    const res = await next.fetch('/buffer', {
      method: 'POST',
      body: 'Hello, world!',
    })
    const json = await res.json()
    expect(json).toEqual({
      'Buffer === B.Buffer': true,
      encoded: Buffer.from('Hello, world!').toString('base64'),
      exposedKeys: expect.arrayContaining([
        '

      method: 'POST',
      body: 'Hello, world!',
    })
    const json = await res.json()
    expect(json).toEqual({
      'B2.Buffer === B.Buffer': true,
      'Buffer === B.Buffer': true,
      'typeof B.Buffer': 'function',
      'typeof B2.Buffer':

constants',
        'kMaxLength',
        'kStringMaxLength',
        'Buffer',
        'SlowBuffer',
      ]),
    })
  })

  it('[pages/api] supports node:buffer', async () => {
    const res = await next.fetch('/api/buffer', {


 to work locally you need to use `pnpm next-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-esm-package/exports'
import * as ExportsNamed from 'my-esm-package/exports'
import { named as namedExports } from 'my-esm-package/exports'

import ImportsDefault from 'my-esm-package/imports'
import * as ImportsNamed from 'my-esm-package/imports'
import { named as namedImports } from 'my-

ort default function Client() {
  return (

Client

Exports

Static

          Default:

{JSON.stringify(ExportsDefault)}

esm-package/imports'

const pendingDynamicExports = import('my-esm-package/exports').then((mod) =>
  JSON.stringify(mod)
)

const pendingDynamicImports = import('my-esm-package/imports').then((mod) =>
  JSON.stringify(mod)
)

exp


 to work locally you need to use `pnpm next-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-cjs-package/exports'
import * as ExportsNamed from 'my-cjs-package/exports'
import { named as namedExports } from 'my-cjs-package/exports'

import ImportsDefault from 'my-cjs-package/imports'
import * as ImportsNamed from 'my-cjs-package/imports'
import { named as namedImports } from 'my-

cjs-package/imports'

const pendingDynamicExports = import('my-cjs-package/exports').then((mod) =>
  JSON.stringify(mod)
)

const pendingDynamicImports = import('my-cjs-package/imports').then((mod) =>
  JSON.stringify(mod)
)

exp


eState } from 'react'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
import { LinkAccordion } from '../../../components/link-accordion'
import { refreshAction } from '../../actions'

export function DynamicRenderCounterClient({ uuid }: { uuid: string }) {
  // Counts how many times this component has received a new uuid from the
  // server. The count lives in React state, so it's preserved when the
  // bfcacheId is stable across navigations and reset when the segment is
  // rec

return
dynamic renders: {count}

}

export function LeafContent() {
  const router = useRouter()
  const pathname = usePathname()
  const searchParams = useSearchParams()
  const { bfcacheId } = router
  const

reated. Useful as a visual signal that the dynamic part re-ran.
  const [count, setCount] = useState(0)
  const [prevUuid, setPrevUuid] = useState(uuid)
  if (prevUuid !== uuid) {
    setPrevUuid(uuid)
    setCount(count + 1)
  }


port { connection } from 'next/server'
import { HydrationIndicator } from '../../hydration-indicator'
import waitForMarkerFile from '../../../waitForMarkerFile'

export default function Page() {
  return (

This is a page with static shell + no streaming metadata

Static shell

        <HydrationIndicator id="shell-hydrated" />

        <Suspense fallback={
Loading...
}>
          <SlowServerComponent /

async function SlowServerComponent() {
  await connection()
  await waitForMarkerFile()
  const randomValue = Math.floor(Math.random() * 1000)
  return (

{`Random value: ${randomValue}`}

      <HydrationIndicator i

>
        </Suspense>
      </div>
    </main>
  )
}


 files: __dirname + '/fixtures/random/cache-components',
        skipDeployment: true,
      })

      if (skipped) {
        return
      }

      it('should not error when accessing middlware that use Math.random()', async () => {
        let res: Awaited<ReturnType<typeof next.fetch>>,
          $: Awaited<ReturnType<typeof next.render$>>

        res = await next.fetch('/rewrite')
        expect(res.status).toBe(200)
        $ = await next.render$('/rewrite')
        expect($('[data-testid="content"]').

  expect(res.status).toBe(200)
        $ = await next.render$('/app/prerendered/unstable-cache')
        expect($('li').length).toBe(2)

        res = await next.fetch('/app/prerendered/use-cache')
        expect(res.status).toBe(200)
        $ = await nex

text()).toBe('rewritten')
      })

      it('should not error when accessing pages that use Math.random() in App Router', async () => {
        let res, $

        res = await next.fetch('/app/prerendered/unstable-cache')


fault Export","named":"EXPORTS NEXT SERVER - Named Export"},"named":"EXPORTS NEXT SERVER - Named Export"}
                 named:
                 "EXPORTS NEXT SERVER - Named Export"
                 Dynamic
                 {"default":{"default":"EXPORTS NEXT SERVER - Default Export","named":"EXPORTS NEXT SERVER - Named Export"},"named":"EXPORTS NEXT SERVER - Named Export"}
               Imports
                 Static
                 Default:
                 {"default":"IMPORTS NEXT SERVER - Default E

RVER - Named Export"}
                 named:
                 "IMPORTS NEXT SERVER - Named Export"
                 Dynamic
                 {"default":{"default":"IMPORTS NEXT SERVER - Default Export","named":"IMPORTS NEXT SERVER - Named Export"},"named"

xport","named":"IMPORTS NEXT SERVER - Named Export"}
                 Namespace:
                 {"default":{"default":"IMPORTS NEXT SERVER - Default Export","named":"IMPORTS NEXT SERVER - Named Export"},"named":"IMPORTS NEXT SE


ext-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-external-cjs-package/exports'
import * as ExportsNamed from 'my-external-cjs-package/exports'
import { named as namedExports } from 'my-external-cjs-package/exports'

import ImportsDefault from 'my-external-cjs-package/imports'
import * as ImportsNamed from 'my-external-cjs-package/imports'
import { named as namedImports } from

 'my-external-cjs-package/imports'

const pendingDynamicExports = import('my-external-cjs-package/exports').then(
  (mod) => JSON.stringify(mod)
)

const pendingDynamicImports = import('my-external-cjs-package/imports').then(
  (


ge with correct UI elements', async () => {
    const browser = await next.browser('/trigger-error')

    // Trigger a client-side error
    await browser.elementByCss('#trigger-error').click()

    // Skip UI checks in dev mode (redbox overlay covers the error page)
    if (isNextDev) {
      await expect(browser).toDisplayRedbox(`
       {
         "description": "Test client error",
         "environmentLabel": null,
         "label": "Runtime Error",
         "source": "app/trigger-error/page.js (9:11)

    }

    // In production mode, verify the client error page UI elements

    // Check that the SVG icon is present (32x32 size)
    const svgIcon = await browser.elementByCss('svg')
    expect(await svgIcon.getAttribute('width')).toBe('32')
    expect(a

@ TriggerErrorPage
       >  9 |     throw new Error('Test client error')
            |           ^",
         "stack": [
           "TriggerErrorPage app/trigger-error/page.js (9:11)",
         ],
       }
      `)
      return


remove this test when the feature is stable
describe('global-not-found - not-present', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should render default 404 when global-not-found is not defined but enabled', async () => {
    const browser = await next.browser('/does-not-exist')
    const bodyText = await browser.elementByCss('body').text()
    expect(bodyText).toBe('404\nThis page could not be found.')
  })

  it('should render custom not-found.js boundary when global-not-f

const browser = await next.browser('/call-not-found')
    const bodyText = await browser.elementByCss('body').text()
    const htmlLang = await browser.elementByCss('html').getAttribute('lang')
    // Render the root layout
    expect(htmlLang).toBe('en')


ly you need to use `pnpm next-with-deps dev|build`
// Make sure you delete node_modules if you are editing the package otherwise it won't
// reinstall and reflect your changes.

import ExportsDefault from 'my-esm-package/exports'
import * as ExportsNamed from 'my-esm-package/exports'
import { named as namedExports } from 'my-esm-package/exports'

import ImportsDefault from 'my-esm-package/imports'
import * as ImportsNamed from 'my-esm-package/imports'
import { named as namedImports } from 'my-esm-package/im

ports'

const pendingDynamicExports = import('my-esm-package/exports').then((mod) =>
  JSON.stringify(mod)
)

const pendingDynamicImports = import('my-esm-package/imports').then((mod) =>
  JSON.stringify(mod)
)

import Client fro


lient'

import { useState, useTransition } from 'react'

export function RevalidateButton({ lang }) {
  const [isPending, startTransition] = useTransition()
  const [result, setResult] = useState(null)

  function handleRevalidate(withSlash) {
    startTransition(async () => {
      try {
        const data = await fetch(
          `/api/revalidate/?lang=${lang}&withSlash=${withSlash}`
        ).then((res) => res.json())
        startTransition(() => {
          setResult(`Revalidated at: ${data.timestamp}`

abled={isPending}
        id="revalidate-button-with-slash"
      >
        {isPending ? 'Revalidating...' : `Revalidate /${lang}/`}
      </button>
      <button
        onClick={handleRevalidate.bind(null, false)}
        disabled={isPending}
        id=

)
        })
      } catch (e) {
        startTransition(() => {
          setResult(`Error: ${e}`)
        })
      }
    })
  }

  return (
    <div>
      <button
        onClick={handleRevalidate.bind(null, true)}
        dis


ribe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'SCSS Support loader handling External imports ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirname,
      dependencies,
      nextConfig,
    })
    it(`should include font on the page`, async () => {
      const

 = await browser.eval(async function () {
        return document.fonts.ready.then((fonts) => {
          const includedFonts = []
          for (const font of fonts.values()) {
            includedFonts.push(font.family)
          }
          return inclu

browser = await next.browser('/')
      const result


ion cachedConsoleCalls(outBadge: string, errBadge: string) {
  'use cache'
  console.info(
    `${outBadge} /console-after-abort/server: template(one: %s, two: %s)`,
    'one',
    'two'
  )
  console.log(
    `${outBadge} /console-after-abort/server: This is a console page` +
      ". Don't match the codeframe."
  )
  console.warn(`${errBadge} /console-after-abort/server: not a template`, {
    foo: 'just-some-object',
  })
  // TODO(veil): Assert on inspected errors once we sourcemap errors replayed from

ssert(
    true,
    `${errBadge} /console-after-abort/server: This is an assert message without a template`
  )
}

let i = 0
export default async function ConsolePage() {
  const outBadge = `:::${i}:out:::`
  const errBadge = `:::${i++}:err:::`

  console

Cache environment.
  // console.error(new Error('/console-after-abort/server: test'))
  console.assert(
    false,
    `${errBadge} /console-after-abort/server: This is an assert message with a %s`,
    'template'
  )
  console.a


e client'

import { use } from 'react'

function log(outBadge: string, errBadge: string) {
  console.info(
    `${outBadge} /console-after-abort/client: template(one: %s, two: %s)`,
    'one',
    'two'
  )
  console.log(
    `${outBadge} /console-after-abort/client: This is a console page. Don't match the codeframe.`
  )
  console.warn(`${errBadge} /console-after-abort/client: not a template`, {
    foo: 'just-some-object',
  })
  console.error(new Error(`${errBadge} /console-after-abort/client: test`))

 without a template`
  )
}

export default function ClientConsolePage({
  data,
  outBadge,
  errBadge,
}: {
  data: Promise<any>
  outBadge: string
  errBadge: string
}) {
  console.log(
    `${outBadge} /console-after-abort/client: logging before prerend

console.assert(
    false,
    `${errBadge} /console-after-abort/client: This is an assert message with a %s`,
    'template'
  )
  console.assert(
    true,
    `${errBadge} /console-after-abort/client: This is an assert message


mport * as path from 'path'
import { nextTestSetup, type Playwright } from 'e2e-utils'

async function assertNoConsoleErrors(browser: Playwright) {
  const logs = await browser.log()
  const warningsAndErrors = logs.filter((log) => {
    return log.source === 'warning' || log.source === 'error'
  })

  expect(warningsAndErrors).toEqual([])
}

describe('view-transitions', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixtures/default'),
  })

  it('smoketest', async () => {

rors(browser)

    // Click the link to navigate to page two
    // The first link causes a sliding transition
    // The second link causes a default transition (cross-fade)
    await browser.elementByCss('a[href="/transition-types/page-two"]').click()

const browser = await next.browser('/basic')

    await assertNoConsoleErrors(browser)
  })

  it('transitionTypes smoketest', async () => {
    const browser = await next.browser('/transition-types')

    await assertNoConsoleEr


e-build-file', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    skipStart: !isNextDev,
    skipDeployment: true,
    env: {
      // Enable persistent caching even when the git working directory is
      // dirty (e.g. when developing Next.js itself). Without this, the
      // cache falls back to a temp directory and persistence/compaction
      // spans are not emitted.
      TURBO_ENGINE_IGNORE_DIRTY: '1',
    },
  })

  if (isNextStart) {
    it('should create .next/trace-build file

      expect(existsSync(traceBuildPath)).toBe(true)
    })

    it('should contain high-level build trace events', async () => {
      // Ensure we have a fresh build
      await next.build()

      const traceBuildPath = join(next.testDir, '.next/trace-b

during production build', async () => {
      // Build the app to trigger trace generation
      await next.build()

      // Check that trace-build file exists
      const traceBuildPath = join(next.testDir, '.next/trace-build')


'

describe('nx-handling', () => {
  const { next } = nextTestSetup({
    skipDeployment: true,
    files: __dirname,
    installCommand: 'npm i',
    buildCommand: 'npm run build',
    startCommand: isNextDev ? 'npm run dev' : 'npm run start',
    packageJson: {
      name: '@nx-next/source',
      version: '0.0.0',
      private: true,
      packageManager: 'npm@10.9.2',
      scripts: {
        // Nx's isolated plugin worker can race in CI and crash before Next.js
        // starts, so keep this fixture

 nx run next-nx-test:serve:production',
      },
      dependencies: {
        react: '19.0.0',
        'react-dom': '19.0.0',
        '@nx/js': '21.1.3',
        '@nx/next': '21.1.3',
        '@nx/workspace': '21.1.3',
        '@swc-node/register': '~1.9.

focused on Next.js integration.
        build:
          'rm -rf dist; NX_ISOLATE_PLUGINS=false nx run next-nx-test:build',
        dev: 'NX_ISOLATE_PLUGINS=false nx run next-nx-test:dev',
        start: 'NX_ISOLATE_PLUGINS=false


 </a>
            </div>
            <div className="logo-container">
              <svg
                fill="currentColor"
                role="img"
                viewBox="0 0 24 24"
                xmlns="http://www.w3.org/2000/svg"
              >


, 'regular'),
  })

  if (isNextDev) {
    // dev doesn't support prefetch={true}, so this just performs a basic test to make sure data is reused for 30s
    it('should return fresh data every navigation', async () => {
      let browser = await next.browser('/', browserConfigWithFixedTime)

      // navigate to prefetch-auto page
      await browser.elementByCss('[href="/1"]').click()

      let initialNumber = await browser.elementById('random-number').text()

      // Navigate back to the index, and then

.elementById('random-number').text()

      expect(newNumber).not.toBe(initialNumber)
    })
  } else {
    describe('prefetch={true}', () => {
      let browser: Playwright

      beforeEach(async () => {
        browser = await next.browser('/', browserC

 back to the prefetch-auto page
      await browser.elementByCss('[href="/"]').click()
      await browser.eval(fastForwardTo, 5 * 1000)
      await browser.elementByCss('[href="/1"]').click()

      let newNumber = await browser


res', 'regular'),
      nextConfig: {
        experimental: { staleTimes: { dynamic: 0 } },
      },
      env: {
        NEXT_TELEMETRY_DEBUG: '1',
      },
    })

    if (isNextDev) {
      // dev doesn't support prefetch={true}, so this just performs a basic test to make sure data is fresh on each navigation
      it('should trigger a loading state before fetching the page, followed by fresh data on every subsequent navigation', async () => {
        const browser = await next.browser('/', browserConfig

ing state is rendered
        await browser
          .elementByCss('[href="/1?timeout=1000"]')
          .click()
          .waitForElementByCss('#loading')

        const initialRandomNumber = await browser
          .waitForElementByCss('#random-number'

WithFixedTime)

        // Wait for initial prefetch to complete before clicking
        await browser.waitForIdleNetwork()

        // this test introduces an artificial delay in rendering the requested page, so we verify a load


s a basic test to make sure data is reused for 30s
    it('should renew the 30s cache once the data is revalidated', async () => {
      let browser = await next.browser('/', browserConfigWithFixedTime)

      // navigate to prefetch-auto page
      await browser.elementByCss('[href="/1"]').click()
      await browser.waitForElementByCss('#random-number')

      let initialNumber = await browser.elementById('random-number').text()

      // Navigate back to the index, and then back to the prefetch-auto page

browser.waitForElementByCss('#random-number')

      let newNumber = await browser.elementById('random-number').text()

      // the number should be the same, as we navigated within 30s.
      expect(newNumber).toBe(initialNumber)

      // Fast forward t

      await browser.elementByCss('[href="/"]').click()
      await browser.waitForElementByCss('[href="/1"]')
      await browser.eval(fastForwardTo, 5 * 1000)
      await browser.elementByCss('[href="/1"]').click()
      await


'
import path from 'path'
import type { Page as PlaywrightPage } from 'playwright'

// TODO: This suite is flaky in production and deploy modes, skip until stabilized.
describe.skip('app dir client cache with parallel routes', () => {
  const { next, isNextDev } = nextTestSetup({
    files: path.join(__dirname, 'fixtures', 'parallel-routes'),
  })

  if (isNextDev) {
    // dev doesn't support prefetch={true}
    it('should skip dev', () => {})
    return
  }

  async function reveal(browser: Playwright, hr

eveal the content.
    await reveal.click()

    // Return the anchor link element.
    return browser.elementByCss(`a[href="${href}"]`)
  }

  describe('prefetch={true}', () => {
    it('should prefetch the full page', async () => {
      let page: Playwr

ef: string) {
    // Get the reveal element and scroll it into view.
    const reveal = await browser.elementByCss(`[data-link-accordion="${href}"]`)
    await reveal.scrollIntoViewIfNeeded()

    // Click the reveal element to r


} from 'e2e-utils'

export const getPathname = (url: string) => {
  const urlObj = new URL(url)
  return urlObj.pathname
}

export const browserConfigWithFixedTime = {
  beforePageLoad: (page) => {
    page.addInitScript(() => {
      const startTime = new Date()
      const fixedTime = new Date('2023-04-17T00:00:00Z')

      // Override the Date constructor
      // @ts-ignore
      // eslint-disable-next-line no-native-reassign
      Date = class extends Date {
        constructor() {
          super()

ment the fixed time by the specified duration
  const currentTime = new Date()
  currentTime.setTime(currentTime.getTime() + ms)

  // Update the Date constructor to use the new fixed time
  // @ts-ignore
  // eslint-disable-next-line no-native-reassign

        // @ts-ignore
          return new startTime.constructor(fixedTime)
        }

        static now() {
          return fixedTime.getTime()
        }
      }
    })
  },
}

export const fastForwardTo = (ms) => {
  // Incre


turn (
    <>

        <Link href="/0?timeout=0" prefetch={true}>
          To Random Number - prefetch: true
        </Link>

        <Link href="/0?timeout=1000" prefetch={true}>
          To Random Number - prefetch: true, slow
        </Link>

        <Link href="/1">To Random Number - prefetch: auto</Link>

        <Link href="/2" prefetch={false}>
          To Random Number 2 - prefetch: false
        </Link>
      </di

prefetch={false}>
          To Random Number 2 - prefetch: false, slow
        </Link>

        <Link href="/1?timeout=1000">
          To Random Number - prefetch: auto, slow
        </Link>

        <Link h

v>
      <div>
        <Link href="/2?timeout=1000"


n (
    <>

        <Link href="/without-loading/0?timeout=0" prefetch={true}>
          To Random Number - prefetch: true
        </Link>

        <Link href="/without-loading/0?timeout=1000" prefetch={true}>
          To Random Number - prefetch: true, slow
        </Link>

        <Link href="/without-loading/1">To Random Number - prefetch: auto</Link>

        <Link href="/without-loading/2" prefetch={false}>
          To

        <Link href="/without-loading/2?timeout=1000" prefetch={false}>
          To Random Number 2 - prefetch: false, slow
        </Link>

        <Link href="/without-loading/1?timeout=1000">
          To

 Random Number 2 - prefetch: false
        </Link>


rowser,
        'description',
        'this is the layout description'
      )
    })

    it('should support title template', async () => {
      const browser = await next.browser('/title-template')
      // Use the parent layout (root layout) instead of app/title-template/layout.tsx
      expect(await browser.eval(`document.title`)).toBe('Page')
    })

    it('should support stashed title in one layer of page and layout', async () => {
      const browser = await next.browser('/title-template/extra')

title when no title is defined in page', async () => {
      const browser = await next.browser('/title-template/use-layout-title')
      expect(await browser.eval(`document.title`)).toBe(
        'title template layout default'
      )
    })

    it('sho

     // Use the parent layout (app/title-template/layout.tsx) instead of app/title-template/extra/layout.tsx
      expect(await browser.eval(`document.title`)).toBe('Extra Page | Layout')
    })

    it('should use parent layout


ge() {
  return (
    <>

{'BEGINNINGasdsadiasdhasuidhasdiuasduhiuihueiohjewiohjewiohj'}

{'asdsadiasdhasuidhasdiuasasdsadduhiuihueiohjewiohjewiohj'}

{'asdasd'}

{'asdasdasadasdasd232344234234234'}

{'asdsadiasdhasuidhasdiuasasdsadduhiuihueiohjewiohjewiohj'}

{'asdasd'}

{'asdasdasadasdasd232344234234234'}

{'asdsadiasdhasuidhasdiuasasdsadduhiuihueiohjewiohjewiohj'}

{'asdasd'}

{'asdasdasada

sdasd232344234234234'}

{'asdsadiasdhasuidhasdiuasduhiuihueiohjewiohjewiohj'}

{'asdsadiasdhasuidhasdiuasasdsadduhiuihueiohjewiohjewiohj'}

{'asdasd'}

{'asdasdasadasdasd23234423423


from 'react'
import type { Metadata } from 'next'
import Link from 'next/link'
import Client from './client'

export default function Page() {
  return (

      <Link id="to-index" href="/">
        to index
      </Link>

      <Link href="/title-template/extra/inner" id="to-nested">
        to /title-template/extra/inner
      </Link>
      <Client />

  )
}

export const metadata: Metadata = {
  generator: 'next.js',
  applicationName: 'test',
  referrer: 'origi

dex, follow',
  alternates: {},
  pagination: {
    previous: '/basic?page=1',
    next: '/basic?page=3',
  },
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
    // Properties set to `true` should not be included in `forma

n-when-cross-origin',
  keywords: ['next.js', 'react', 'javascript'],
  authors: [{ name: 'huozhi' }, { name: 'tree', url: 'https://tree.com' }],
  manifest: '/api/manifest',
  creator: 'shu',
  publisher: 'vercel',
  robots: 'in


'

export const runtime = 'edge'

export default function Page() {
  return (

      <Link id="to-index" href="/">
        to index
      </Link>

      <Link href="/title-template/extra/inner" id="to-nested">
        to /title-template/extra/inner
      </Link>
      <Client />

  )
}

export const metadata: Metadata = {
  generator: 'next.js',
  applicationName: 'test',
  referrer: 'origin-when-cross-origin',
  keywords: ['next.js', 'react', 'javascript'],
  autho

://tree.com' }],
  manifest: '/api/manifest',
  robots: 'index, follow',
  alternates: {},
  pagination: {
    previous: '/basic?page=1',
    next: '/basic?page=3',
  },
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
  },

rs: [{ name: 'huozhi' }, { name: 'tree', url: 'https


 { nextTestSetup } from 'e2e-utils'

describe('cache-components PPR bot static generation bypass', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should bypass static generation for DOM bot requests to avoid SSG_BAILOUT', async () => {
    const res = await next.fetch('/foo', {
      headers: {
        'user-agent': 'Googlebot',
      },
    })
    // With cache components + PPR enabled, DOM bots should behave like regular users
    // and use the fallback cache mechanism. This

    // Check that the page rendered successfully
    // With PPR, content is streamed via script tags
    expect(html).toContain('\\"children\\":\\"foo\\"')

    // Verify Math.random() was executed (check for a decimal number in the streamed content)

 allows them to handle dynamic content
    // like Math.random() without triggering SSG_BAILOUT errors.
    expect(res.status).toBe(200)

    // Verify that the response contains the page content
    const html = await res.text()


retry } from 'next-test-utils'

describe('interception-dynamic-segment-middleware', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should work when interception route is paired with a dynamic segment & middleware', async () => {
    const browser = await next.browser('/')

    await browser.elementByCss('[href="/foo/p/1"]').click()
    await retry(async () => {
      expect(await browser.elementById('modal').text()).toMatch(/intercepted/)
    })
    await browser.refresh()

      )
    })
  })

  it('should intercept with back/forward navigation with middleware', async () => {
    // Test that interception works correctly with middleware and browser navigation
    const browser = await next.browser('/')

    // Navigate with

await retry(async () => {
      expect(await browser.elementById('modal').text()).toBe('default')
    })
    await retry(async () => {
      expect(await browser.elementById('children').text()).toMatch(
        /not intercepted/


routes-breadcrumbs', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should provide an unmatched catch-all route with params', async () => {
    const browser = await next.browser('/')
    await browser.elementByCss("[href='/artist1']").click()

    const slot = await browser.waitForElementByCss('#slot')

    // verify page is rendering the params
    expect(await browser.elementByCss('h2').text()).toBe('Artist: artist1')

    // verify slot is rendering the params
    expect(aw

um2']").click()

    await retry(async () => {
      // verify page is rendering the params
      expect(await browser.elementByCss('h2').text()).toBe('Album: album2')
    })

    // verify slot is rendering the params
    expect(await slot.text()).toConta

ait slot.text()).toContain('Artist: artist1')
    expect(await slot.text()).toContain('Album: Select an album')
    expect(await slot.text()).toContain('Track: Select a track')

    await browser.elementByCss("[href='/artist1/alb


he layout manually
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'app-dir create root layout',
  () => {
    const isDev = (global as any).isNextDev

    if ((global as any).isNextDeploy) {
      it('should skip next deploy for now', () => {})
      return
    }

    if (isDev) {
      describe('page.js', () => {
        describe('root layout in app', () => {
          const { next } = nextTestSetup({
            files: {
              app: new FileRef(path.join(__dirname, 'app')),

tput.length
            const browser = await next.browser('/route')

            expect(await browser.elementById('page-text').text()).toBe(
              'Hello world!'
            )

            await check(
              () => stripAnsi(next.cliOutput.

      'next.config.js': new FileRef(
                path.join(__dirname, 'next.config.js')
              ),
            },
          })

          it('create root layout', async () => {
            const outputIndex = next.cliOu


t { next, isNextDev, isNextStart } = nextTestSetup({
    files: __dirname,
  })

  it('should generate an opengraph image with a metadata route handler that uses "use cache"', async () => {
    const res = await next.fetch('/opengraph-image')
    expect(res.status).toBe(200)
    expect(res.headers.get('content-type')).toBe('image/png')

    if (isNextStart) {
      const [buildStatus] = next.cliOutput.match(/. \/opengraph-image/)

      // TODO: Should always be `○ /opengraph-image`.
      expect(buildStatu

tch('/icon')
    expect(res.status).toBe(200)
    expect(res.headers.get('content-type')).toBe('image/png')

    if (isNextStart) {
      const [buildStatus] = next.cliOutput.match(/. \/icon/)

      // TODO: Should always be `○ /icon`.
      expect(buildS

s).toBeOneOf([
        '○ /opengraph-image',
        'ƒ /opengraph-image',
      ])
    }
  })

  it('should generate an icon image with a metadata route handler that uses "use cache"', async () => {
    const res = await next.fe


rt { ImageResponse } from 'next/og'

export const alt = 'About Acme'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

async function fetchPostData() {
  'use cache'

  return { title: 'Test', created: Date.now() }
}

export default async function Image() {
  const post = await fetchPostData()

  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 48,
          background: 'white',
          width: '100%',
          height: '100%',

justifyContent: 'center',
          flexDirection: 'column',
        }}
      >

{post.title}

          {new Date(post.created).toLocaleTimeString()}

    ),
    size
  )

 display: 'flex',
          alignItems: 'center',


retry } from 'next-test-utils'

describe('next/script beforeInteractive inline payload escaping', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should html-escape forwarded string props so they cannot break out of the inline __next_s script', async () => {
    const html = await next.render('/')

    // The attacker-controlled prop values must not appear verbatim in the HTML.
    // If they do, the `</script>` inside terminates the inline __next_s push
    // script at the HTM

lineChildren=true</script>'
    )
    expect(html).not.toContain('</script><script>window.__xssSrc=true</script>')

    // The fixture's <PwnDetector /> exposes each result as a `data-*`
    // attribute on `[data-testid="xss-status"]`. `data-ready="true"`

L tokenizer level and the trailing <script> executes.
    expect(html).not.toContain(
      '</script><script>window.__xssInlineInnerHTML=true</script>'
    )
    expect(html).not.toContain(
      '</script><script>window.__xssIn


script'
import { PwnDetector } from './xss-detector'

// Regression fixture for HTML-escaping of the inline __next_s payload that
// Next.js emits for `beforeInteractive` scripts. Any string prop forwarded
// through `restProps` (here `data-tracking-id`, but `id` and any other
// attribute are equivalent) reaches the inline <script> body via
// JSON.stringify. Without HTML escaping, a value like
// `</script><script>...</script>` breaks out of the script element at the
// HTML tokenizer level, executes, and

acking-id="</script><script>window.__xssInlineInnerHTML=true</script>"
        dangerouslySetInnerHTML={{
          // The body evaluates a `<` comparison so the global doubles as proof
          // of both "did this run" and "did the HTML-escape preserve

 the fingerprint it leaves on `window`
// is picked up by <PwnDetector />.
export default function Page() {
  return (
    <div>
      <Script
        id="inline-innerhtml-xss"
        strategy="beforeInteractive"
        data-tr


 on:
//
// 1. Whether any malicious injected `<script>` executed. Each would set a
//    `__xss*` global from its `</script><script>...</script>` break-out.
// 2. Whether each legitimate beforeInteractive `<Script>` actually ran AND,
//    for the inline ones, that the HTML-escape round-trip preserved the
//    source verbatim. The inline scripts store the value of an expression
//    containing `<`, `>`, or `&` — any corruption would either throw or
//    produce a non-true value and the proof global would

 boolean `data-*` attribute for simple per-result querying
// from tests.
type Report = {
  xssInlineInnerHTML: boolean
  xssInlineChildren: boolean
  xssSrc: boolean
  escapeProofInlineInnerHTML: boolean
  escapeProofInlineChildren: boolean
  loadedSrc: b

 fail the `=== true`
//    check. The external-src script only needs to confirm it loaded, so it
//    uses a plain flag (`__loadedSrc`).
//
// Each result is both rendered as human-readable text for debugging and
// exposed as a


 {import('next').NextConfig}
 */
const nextConfig = {
  cacheComponents: true,
  experimental: {
    optimisticRouting: true,
  },
  // The bug being regressed requires the response for /[teamSlug] to
  // exercise its `@actions/[...catchAll]` parallel slot even though the
  // canonical URL has no parts left to feed the catch-all. The simplest
  // reproducer is a rewrite that maps the single-segment URL into a
  // longer destination: the response describes a route shape that
  // includes the catch-all s

anonical URL is short enough
  // that no parts reach the catch-all under normal routing.
  async rewrites() {
    return [
      {
        source: '/:teamSlug',
        destination: '/:teamSlug/overview',
      },
    ]
  },
}

module.exports = nextConfig


stSetup } from 'e2e-utils'
import { waitForRedbox, getRedboxSource } from 'next-test-utils'

describe('Invalid Global CSS with Custom App', () => {
  const { next, skipped, isTurbopack, isRspack } = nextTestSetup({
    files: __dirname,
    skipStart: isNextStart,
    skipDeployment: true,
    dependencies: { sass: '1.54.0' },
  })

  if (skipped) {
    return
  }

  if (isNextStart) {
    it('should fail to build', async () => {
      const { exitCode, cliOutput } = await next.build()
      expect(exitCode

y global CSS imports.*?pages(\/|\\)_app/
      )
      // Skip: Rspack loaders cannot access module issuer info for location details
      if (!process.env.NEXT_RSPACK) {
        expect(cliOutput).toMatch(/Location:.*pages[\\/]index\.js/)
      }
    })

).not.toBe(0)
      if (!isTurbopack) {
        expect(cliOutput).toContain('Failed to compile')
      }
      expect(cliOutput).toContain('styles/global.scss')
      expect(cliOutput).toMatch(
        /Please move all first-part


ependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      ...nextConfig,
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])('SCSS Support ($dependencies)', ({ dependencies, nextConfig }) => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    // This test is skipped because it is reading files in the `.next` file which
    // isn't available/necessary in a deployment environment.
    skipDeployment: true,
    dependencies,
    nextCo

compiled and prefixed`, async () => {
        const $ = await next.render$('/')

        const cssSheet = $('link[rel="stylesheet"]')
        expect(cssSheet.length).toBe(1)

        const stylesheetUrl = cssSheet.attr('href')

        const cssContent = a

nfig,
  })

  if (skipped) return // TODO: Figure out this test for dev and Turbopack
  ;(isNextDev ? describe.skip : describe)('Production only', () => {
    describe('CSS Compilation and Prefixing', () => {
      it(`should've


mistic routing - parallel slot catch-all regression', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  if (isNextDev) {
    // Optimistic routing is a production-build feature; in dev mode the
    // router does not have complete information about which routes
    // exist, so prediction is disabled.
    test('skipped in dev mode', () => {})
    return
  }

  // Regression test: a route with a parallel slot whose route is a
  // required catch-all (e.g., /[teamSlug] with a

ch-all, resolving the URL to the team-page
  // content even though /myteam/myproject is a separate route. The
  // router skipped the server fetch entirely under the (incorrect)
  // assumption that the URL was already known.
  //
  // Detection: visit /m

n
  // `@actions/[...catchAll]` slot) used to poison route prediction.
  // After visiting /myteam, navigating to a longer sibling URL like
  // /myteam/myproject would reuse a prediction derived from the
  // @actions slot's cat


from 'e2e-utils'
import type * as Playwright from 'playwright'
import { createRouterAct } from 'router-act'

describe('client params', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })
  if (isNextDev) {
    test('prefetching is disabled', () => {})
    return
  }

  it('client segments that access dynamic params are fully statically prefetchable', async () => {
    let act: ReturnType<typeof createRouterAct>
    const browser = await next.browser('/', {
      beforePageLoad(p

// be able to fully prefetch them, without invoking a dynamic server render.
    const toggleLinkVisibility = await browser.elementByCss(
      'input[data-link-accordion="/clothing/1"]'
    )
    await act(async () => {
      await toggleLinkVisibility.cl

: Playwright.Page) {
        act = createRouterAct(p)
      },
    })

    // Prefetch the page. Although this page access dynamic params, it only
    // does so inside segments that are marked with "use cache". So we should


act'

function Content({
  params,
  searchParams,
}: {
  params: Promise<{ product: string }>
  searchParams: Promise<Record<string, string | string[] | undefined>>
}) {
  const { product } = use(params)
  const searchParamsDict = use(searchParams)

  let query = null
  if (Object.keys(searchParamsDict).length > 0) {
    query = JSON.stringify(searchParamsDict)
  }

  return (
    <>

Product: {product}

Query: {query ? query : '(none)'}

    </>
  )
}

export

rams,
}: {
  params: Promise<{ product: string }>
  searchParams: Promise<Record<string, string | string[] | undefined>>
}) {
  return (
    <Suspense fallback="Loading...">
      <Content params={params} searchParams={searchParams} />
    </Suspense>
  )

 default function ProductPage({
  params,
  searchPa


BrowserWithFakeClock(url: string) {
    let page!: Playwright.Page
    const startDate = Date.now()

    const browser = await next.browser(url, {
      async beforePageLoad(p: Playwright.Page) {
        page = p
        await page.clock.install()
        await page.clock.setFixedTime(startDate)
      },
    })

    const act = createRouterAct(page)

    return { browser, page, act, startDate }
  }

  it('reuses dynamic data within the per-page stale time window', async () => {
    const { browser, page, ac

Css(
          'input[data-link-accordion="/per-page-config/dynamic-stale-60"]'
        )
        await toggle.click()
        const link = await browser.elementByCss(
          'a[href="/per-page-config/dynamic-stale-60"]'
        )
        await link.cli

t, startDate } =
      await startBrowserWithFakeClock('/per-page-config')

    // Navigate to the dynamic page with unstable_dynamicStaleTime = 60
    await act(
      async () => {
        const toggle = await browser.elementBy


v } = nextTestSetup({
    files: __dirname,
  })
  if (isNextDev) {
    test('disabled in development / deployment', () => {})
    return
  }

  it('entry expires when its stale time has elapsed', async () => {
    let page: Playwright.Page
    const browser = await next.browser('/', {
      beforePageLoad(p: Playwright.Page) {
        page = p
      },
    })
    const act = createRouterAct(page)

    await page.clock.install()

    // Reveal the link to trigger a prefetch
    const toggle2MinutesLink = aw

nc () => {
        await toggle2MinutesLink.click()
        await browser.elementByCss('a[href="/stale-2-minutes"]')
      },
      {
        includes: 'Content with stale time of 2 minutes',
      }
    )
    await act(
      async () => {
        await t

ait browser.elementByCss(
      'input[data-link-accordion="/stale-2-minutes"]'
    )
    const toggle4MinutesLink = await browser.elementByCss(
      'input[data-link-accordion="/stale-4-minutes"]'
    )
    await act(
      asy


stSetup } from 'e2e-utils'
import { waitForRedbox, getRedboxSource } from 'next-test-utils'

describe('Valid and Invalid Global CSS with Custom App', () => {
  const { next, skipped, isTurbopack, isRspack } = nextTestSetup({
    files: __dirname,
    skipStart: isNextStart,
    skipDeployment: true,
    dependencies: { sass: '1.54.0' },
  })

  if (skipped) {
    return
  }

  if (isNextStart) {
    it('should fail to build', async () => {
      const { exitCode, cliOutput } = await next.build()
      expec

l first-party global CSS imports'
      )
      // Skip: Rspack loaders cannot access module issuer info for location details
      if (!process.env.NEXT_RSPACK) {
        expect(cliOutput).toMatch(/Location:.*pages[\\/]index\.js/)
      }
    })
  } else

t(exitCode).not.toBe(0)
      if (!isTurbopack) {
        expect(cliOutput).toContain('Failed to compile')
      }
      expect(cliOutput).toContain('styles/global.scss')
      expect(cliOutput).toContain(
        'Please move al


 eslint-env jest */

import { nextTestSetup } from 'e2e-utils'
import { colorToRgb } from 'next-test-utils'

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Has CSS Module in computed styles in Development ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirnam

dencies,
      nextConfig,
    })

    it('should have CSS for page', async () => {
      const browser = await next.browser('/')
      expect(
        await browser.elementByCss('#verify-red').getComputedCss('color')
      ).toBe(colorToRgb('red'))
    })


from 'e2e-utils'

describe('app-dir - metadata-icons-parallel-routes', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should present favicon with other icons when parallel routes are presented', async () => {
    const $ = await next.render$('/')
    expect($('link[type="image/x-icon"]').length).toBe(1)
    expect($('link[type="image/svg+xml"]').length).toBe(1)
    expect($('link[rel="apple-touch-icon"]').length).toBe(1)
  })

  it('should render both icon.png and icon.svg when

nk[rel="icon"][type="image/svg+xml"]')

    expect(pngIcon.length).toBe(1)
    expect(svgIcon.length).toBe(1)

    // Verify the URLs are distinct
    expect(pngIcon.attr('href')).toMatch(/icon\.png/)
    expect(svgIcon.attr('href')).toMatch(/icon\.svg/)

 both are present', async () => {
    const $ = await next.render$('/')

    // Should have both PNG and SVG icons for browser fallback support
    const pngIcon = $('link[rel="icon"][type="image/png"]')
    const svgIcon = $('li


mport Link from 'next/link'

export default async function Page(props) {
  const searchParams = await props.searchParams
  return (
    <>

{JSON.stringify(searchParams)}

      <Link href="/search">Go to search</Link>

          <Link href="/search-params?id=1">/search-params?id=1</Link>

          <Link href="/search-params?id=2">/search-params?id=2</Link>

          <Link href="/search

</Link>

          <Link href="/params-first" prefetch={false}>
            /params-first
          </Link>

          <Link href="/root-page-first" prefetch={false}>
            /root-page-first

-params?id=3" prefetch={true}>
            /search-params?id=3 (prefetch: true)
          </Link>
        </li>
        <li>
          <Link href="/search-params" prefetch={true}>
            /search-params (prefetch: true)


() => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should match default and dynamic segment paths before catch-all', async () => {
    let browser = await next.browser('/en/catchall/page')

    // we have a top-level catch-all
    expect(await browser.elementById('children').text()).toBe(
      '/[locale]/[[...catchAll]]/page.tsx'
    )

    browser = await next.browser('/en/nested')

    // we're now at the /[locale]/nested segment, which overrides the top-level catch-all, and the

ct(await browser.elementById('slot0').text()).toBe(
      '/[locale]/nested/@slot0/default.tsx'
    )

    // since there is a default defined in @slot1, we expect that to match
    expect(await browser.elementById('slot1').text()).toBe(
      '/[locale]/n

re is a page defined to be matched
    expect(await browser.elementById('nested-children').text()).toBe(
      '/[locale]/nested/page.tsx'
    )

    // since there is a default defined in @slot0, we expect that to match
    expe


ype Playwright } from 'e2e-utils'

describe('parallel-routes-catchall-css', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  async function getChildrenBackgroundColor(browser: Playwright) {
    return browser.eval(
      `window.getComputedStyle(document.getElementById('main')).backgroundColor`
    )
  }

  async function getSlotBackgroundColor(browser: Playwright) {
    return browser.eval(
      `window.getComputedStyle(document.getElementById('slot')).backgroundColor`
    )
  }

oBe('rgb(0, 0, 255)')

    expect(await browser.elementByCss('title').text()).toBe('Home Page')
    expect(await browser.elementsByCss('title')).toHaveLength(1)

    // navigate to the page that matches a parallel route
    await browser.elementByCss("[hre

 it('should properly load the Head content from multiple leaf segments', async () => {
    const browser = await next.browser('/')

    // the page background should be blue
    expect(await getChildrenBackgroundColor(browser)).t


as useAppRouter,
  useSearchParams,
} from 'next/navigation'
import { useState, useEffect } from 'react'

export const RouterHooksFixtures = () => {
  const pagesRouter = usePagesRouter()
  const appRouter = useAppRouter()
  const searchParams = useSearchParams()
  const pathname = usePathname()

  const [value, setValue] = useState(null)
  useEffect(() => {
    if (!pagesRouter.isReady) {
      return
    }

    setValue(searchParams.get('key'))
  }, [pagesRouter.isReady, searchParams])

  const onClick =

}

  return (

Value:{value}

{pathname}

      <button type="button" onClick={onClick}>
        Push
      </button>

() => {
    appRouter.push('/adapter-hooks/pushed')


te { foo: 'just-some-object' }
       Error: :::0:err::: /console: test
           at ConsolePage (app/console/page.tsx:<line>:<col>)
         40 |   })
         41 |   await 1
       > 42 |   console.error(new Error(\`\${errBadge} /console: test\`))
            |                 ^
         43 |   await 1
         44 |

[32m'just-some-object' }
       Assertion failed: :::0:err::: /console: This is an assert message with a template
        Cache  :::0:err::: /console: not a template { foo: 'just-some-object' }
       Assertion failed:  C

   console.assert(
         45 |     false,
       Assertion failed: :::0:err::: /console: This is an assert message with a template
       :::0:err::: /console: not a template { foo:


oleCalls(outBadge: string, errBadge: string) {
  'use cache'
  console.info(`${outBadge} /console: template(one: %s, two: %s)`, 'one', 'two')
  await 1
  console.log(
    `${outBadge} /console: This is a console page` +
      ". Don't match the codeframe."
  )
  await 1
  console.warn(`${errBadge} /console: not a template`, {
    foo: 'just-some-object',
  })
  await 1
  // TODO(veil): Assert on inspected errors once we sourcemap errors replayed from Cache environment.
  // console.error(new Error('/console

let i = 0
export default async function ConsolePage() {
  const outBadge = `:::${i}:out:::`
  const errBadge = `:::${i++}:err:::`
  console.info(`${outBadge} /console: template(one: %s, two: %s)`, 'one', 'two')
  await 1
  console.log(
    `${outBadge} /

: test'))
  console.assert(
    false,
    `${errBadge} /console: This is an assert message with a %s`,
    'template'
  )
  console.assert(
    true,
    `${errBadge} /console: This is an assert message without a template`
  )
}


nv jest */

import { nextTestSetup } from 'e2e-utils'
import { colorToRgb } from 'next-test-utils'

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Dynamic Route CSS Module Usage ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirname,
      dependencies,

rectly', async () => {
      const browser = await next.browser('/post-1')

      const background = await browser
        .elementByCss('#my-div')
        .getComputedCss('background-color')

      expect(background).toMatch(colorToRgb('red'))
    })
  }

  nextConfig,
    })
    it('should apply styles cor


* eslint-env jest */

import { nextTestSetup } from 'e2e-utils'
import { colorToRgb } from 'next-test-utils'

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Catch-all Route CSS Module Usage ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirname,
      depend

nextConfig,
    })

    it('should render the module', async () => {
      const browser = await next.browser('/post')
      expect(
        await browser.elementByCss('#my-div').getComputedCss('background-color')
      ).toBe(colorToRgb('red'))
    })
  }


ext-test-utils'

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'CSS Module Composes Usage (External) ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirname,
      dependencies,
      nextConfig,
    })

    it('should render the module', async () => {

(
        await browser.elementByCss('#verify-yellow').getComputedCss('color')
      ).toBe(colorToRgb('yellow'))
      expect(
        await browser
          .elementByCss('#verify-yellow')
          .getComputedCss('background-color')
      ).toBe(color

const browser = await next.browser('/')
      expect


t nextConfig = {
  turbopack: {
    resolveAlias: {
      '/*': './*',
      '~*': '*',
    },
  },
}

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      ...nextConfig,
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Good CSS Import from node_modules with tilde ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirnam

      nprogress: '0.2.0',
      },
      nextConfig,
    })

    it('should render the page', async () => {
      const browser = await next.browser('/')
      expect(
        await browser
          .elementByCss('#nprogress .bar')
          .getComputedC

e,
      dependencies: {
        ...dependencies,


/* eslint-env jest */
import { nextTestSetup } from 'e2e-utils'

describe('SCSS Support', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  // Production only test
  ;(isNextDev ? describe.skip : describe)('Friendly Webpack Error', () => {
    it('should be a friendly error successfully', async () => {
      const { exitCode, cliOutput } = await next.build()
      expect(exitCode).toBe(1)

      expect(cliOutput).toContain('./st

de your workspace.'
      )
      expect(cliOutput).toContain(
        'Learn more: https://nextjs.org/docs/messages/install-sass'
      )

      expect(cliOutput).not.toContain('css-loader')
      expect(cliOutput).not.toContain('sass-loader')
    })
  })

yles/global.scss')
      expect(cliOutput).toContain(
        "To use Next.js' built-in Sass support, you first need to install `sass`."
      )
      expect(cliOutput).toContain(
        'Run `npm i sass` or `yarn add sass` insi


 - draft mode', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  async function runTests({ basePath = '/' }: { basePath: string }) {
    let origRandHome = 'unintialized'
    let origRandWithCookies = 'unintialized'
    let Cookie = ''

    it(`should use initial rand when draft mode is disabled on ${basePath}index`, async () => {
      const $ = await next.render$(basePath)
      expect($('#mode').text()).toBe('DISABLED')
      expect($('#rand').text()).toBeDefined()

').text()).toBe('DISABLED')
      expect($('#rand').text()).toBeDefined()
      expect($('#data').text()).toBe('')
      origRandWithCookies = $('#rand').text()
    })

    if (!isNextDev) {
      if (basePath === '/') {
        it('should not generate ran

  origRandHome = $('#rand').text()
    })

    it(`should use initial rand when draft mode is disabled on ${basePath}with-cookies`, async () => {
      const $ = await next.render$(`${basePath}with-cookies`)
      expect($('#mode


 Value: test')

    // One more time!
    await browser.elementByCss('input').type('another')
    await browser.elementByCss('button').click()

    const newLoading = await browser.waitForElementByCss('#loading')
    expect(await newLoading.text()).toBe('Loading...')

    const newSearchValue = await browser.waitForElementByCss('#search-value')
    expect(await newSearchValue.text()).toBe('Search Value: another')
  })

  it('should properly render root page with searchParams when prefetch is aliased', async

":"1"}')
  })

  it('should reflect the correct searchParams when re-using the same page segment', async () => {
    const browser = await next.browser('/')
    await browser.elementByCss("[href='/params-first']").click()
    await browser.elementByCss("[h

 () => {
    const browser = await next.browser('/search-params')
    await browser.elementByCss("[href='/?id=1']").click()
    const params = await browser.waitForElementByCss('#root-params').text()
    expect(params).toBe('{"id


lient'

import { useSearchParams, ReadonlyURLSearchParams } from 'next/navigation'
import { useSyncExternalStore } from 'react'

export default function Page() {
  const searchParams = useSearchParams()
  const searchParamsClient = useSyncExternalStore(
    () => {
      return () => {}
    },
    () => {
      return searchParams
    },
    () => {
      return null
    }
  )

  return (

        server:{' '}

          {searchP

        client:{' '}
        <span data-testid="client">
          {searchParamsClient === null
            ? '<pending>'
            : searchParamsClient instanceof ReadonlyURLSearchParams
              ? 'PASS instanceof check'
              : `FAILED R

arams instanceof ReadonlyURLSearchParams
            ? 'PASS instanceof check'
            : `FAILED Received: "${String(searchParams)}" instead instanceof ${searchParams.constructor.name}`}
        </span>
      </li>
      <li>


ion cachedConsoleCalls(outBadge: string, errBadge: string) {
  'use cache'
  console.info(
    `${outBadge} /console-after-abort/server: template(one: %s, two: %s)`,
    'one',
    'two'
  )
  console.log(
    `${outBadge} /console-after-abort/server: This is a console page` +
      ". Don't match the codeframe."
  )
  console.warn(`${errBadge} /console-after-abort/server: not a template`, {
    foo: 'just-some-object',
  })
  // TODO(veil): Assert on inspected errors once we sourcemap errors replayed from

ssert(
    true,
    `${errBadge} /console-after-abort/server: This is an assert message without a template`
  )
}

let i = 0
export default async function ConsolePage() {
  const outBadge = `:::${i}:out:::`
  const errBadge = `:::${i++}:err:::`

  console

Cache environment.
  // console.error(new Error('/console-after-abort/server: test'))
  console.assert(
    false,
    `${errBadge} /console-after-abort/server: This is an assert message with a %s`,
    'template'
  )
  console.a


 from 'e2e-utils'
import { colorToRgb } from 'next-test-utils'

const sassOptions = {
  prependData: `
    $var: red;
  `,
}

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: { sassOptions } },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        ...sassOptions,
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Basic Module Prepend Data Support ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextT

s,
      nextConfig,
    })

    it('should render the module', async () => {
      const browser = await next.browser('/')
      expect(
        await browser.elementByCss('#verify-red').getComputedCss('color')
      ).toBe(colorToRgb('red'))
    })
  }
)

estSetup({
      files: __dirname,
      dependencie


int-env jest */

import { nextTestSetup } from 'e2e-utils'
import { colorToRgb } from 'next-test-utils'

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Has CSS Module in computed styles in Production ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next } = nextTestSetup({
      files: __dirname,

es,
      nextConfig,
    })

    it('should render the page', async () => {
      const browser = await next.browser('/')
      expect(
        await browser.elementByCss('#verify-red').getComputedCss('color')
      ).toBe(colorToRgb('red'))
    })
  }
)


     { pathname: '/adapter-hooks/static' },
      { pathname: '/adapter-hooks/1' },
      { pathname: '/adapter-hooks/2' },
      { pathname: '/adapter-hooks/1/account' },
      { pathname: '/adapter-hooks/static', keyValue: 'value' },
      { pathname: '/adapter-hooks/1', keyValue: 'value' },
      { pathname: '/adapter-hooks/2', keyValue: 'value' },
      { pathname: '/adapter-hooks/1/account', keyValue: 'value' },
    ])(
      'should have the correct hooks at $pathname',
      async ({ pathname, keyVal

'key-value').text()).toBe(
          `Value:${keyValue}`
        )
        expect(await browser.elementById('pathname').text()).toBe(pathname)

        await browser.elementByCss('button').click()
        await browser.waitForElementByCss('#pushed', { stat

ue = '' }) => {
        const browser = await next.browser(
          pathname + (keyValue ? `?key=${keyValue}` : '')
        )

        await browser.waitForElementByCss('#router-ready')
        expect(await browser.elementById(


port { nextTestSetup } from 'e2e-utils'
import { colorToRgb, getUrlFromBackgroundImage } from 'next-test-utils'

// TODO: Skipped as this test should set up the server to handle assetPrefix which it currently does not do.
describe.skip('SCSS Support loader handling', () => {
  describe.each([
    { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
    {
      dependencies: { 'sass-embedded': '1.75.0' },
      nextConfig: {
        sassOptions: {
          implementation: 'sass-embedded',
        },

extConfig,
      })

      it('should render the page', async () => {
        const browser = await next.browser('/')
        expect(
          await browser.elementByCss('.red-text').getComputedCss('color')
        ).toBe(colorToRgb('red'))

        const

      },
    },
  ])(
    'CSS URL via `file-loader` and asset prefix (1) ($dependencies)',
    ({ dependencies, nextConfig }) => {
      const { next } = nextTestSetup({
        files: __dirname,
        dependencies,
        n


port { nextTestSetup } from 'e2e-utils'
import { colorToRgb, retry } from 'next-test-utils'

describe.each([
  { dependencies: { sass: '1.54.0' }, nextConfig: undefined },
  {
    dependencies: { 'sass-embedded': '1.75.0' },
    nextConfig: {
      sassOptions: {
        implementation: 'sass-embedded',
      },
    },
  },
])(
  'Can hot reload CSS Module without losing state ($dependencies)',
  ({ dependencies, nextConfig }) => {
    const { next, isNextDev } = nextTestSetup({
      files: __dirname,

ser('/')

        const desiredText = 'hello world'
        await browser.elementById('text-input').type(desiredText)
        expect(await browser.elementById('text-input').getValue()).toBe(
          desiredText
        )

        expect(
          await

  dependencies,
      nextConfig,
    })
    ;(isNextDev ? describe : describe.skip)('development only', () => {
      it('should update CSS color without remounting <input>', async () => {
        const browser = await next.brow


tTestSetup } from 'e2e-utils'

describe('webpack-loader-module-type', () => {
  const { next, isTurbopack, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) return

  // bytes type is Turbopack-only, webpack doesn't have a direct equivalent
  const itTurbopackOnly = isTurbopack ? it : it.skip

  it('should load svg as asset/resource and return URL', async () => {
    const $ = await next.render$('/')
    const src = $('#svg-url').text()
    // asset/resource sh

async () => {
      const $ = await next.render$('/')
      const bytesType = $('#bytes-type').text()
      const bytesLength = $('#bytes-length').text()
      const bytesText = $('#bytes-text').text()

      // eslint-disable-next-line jest/no-standalone-

ould emit the file and return URL path
    expect(src).toMatch(
      /\/_next\/static\/(immutable\/)?media\/test\.[0-9a-z_-]+\.svg$/
    )
  })

  itTurbopackOnly(
    'should load data file as bytes and return Uint8Array',


e client'

import { use } from 'react'

function log(outBadge: string, errBadge: string) {
  console.info(
    `${outBadge} /console-after-abort/client: template(one: %s, two: %s)`,
    'one',
    'two'
  )
  console.log(
    `${outBadge} /console-after-abort/client: This is a console page. Don't match the codeframe.`
  )
  console.warn(`${errBadge} /console-after-abort/client: not a template`, {
    foo: 'just-some-object',
  })
  console.error(new Error(`${errBadge} /console-after-abort/client: test`))

 without a template`
  )
}

export default function ClientConsolePage({
  data,
  outBadge,
  errBadge,
}: {
  data: Promise<any>
  outBadge: string
  errBadge: string
}) {
  console.log(
    `${outBadge} /console-after-abort/client: logging before prerend

console.assert(
    false,
    `${errBadge} /console-after-abort/client: This is an assert message with a %s`,
    'template'
  )
  console.assert(
    true,
    `${errBadge} /console-after-abort/client: This is an assert message


 let act: ReturnType<typeof createRouterAct>
    const browser = await next.browser('/', {
      beforePageLoad(page) {
        act = createRouterAct(page)
      },
    })

    await act(
      async () => {
        // Reveal the link to trigger a prefetch, but block the responses.
        const link = await act(async () => {
          const reveal = await browser.elementByCss('input[type="checkbox"]')
          await reveal.click()
          return await browser.elementByCss('a')
        }, 'block')

'Dynamic in nav',
          }
        )

        // The static and dynamic content appears simultaneously because everything
        // was fetched as part of the same navigation request.
        const nav = await browser.elementById('nav')
        expect(

   // While the prefetches are blocked, navigate to the test page.
        await act(
          async () => {
            // Navigate to the test page
            await link.click()
          },
          {
            includes:


pe * as Playwright from 'playwright'
import { createRouterAct } from 'router-act'

/**
 * When a dynamic param contains a percent-encoded forward slash (`%2F`), the
 * client double-encodes the URL part when deriving its segment cache key, while
 * the server encodes the decoded value once. The resulting segment mismatch
 * causes the navigation reducer to invalidate the entire route cache, so any
 * later prefetch for the same URL re-fetches the route tree
 * (`next-router-segment-prefetch: /_tree`).
 *
 *

ms', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  if (isNextDev) {
    test('prefetching is disabled in dev mode', () => {})
    return
  }

  describe.each([
    { label: 'unencoded param', href: '/foo' },
    { labe

 The fixture is intentionally fully dynamic (no `generateStaticParams`): a
 * statically prerendered file is served from the CDN without the `%2F`
 * round-trip the bug depends on.
 */
describe('segment cache - encoded slash para


 in development / deployment', () => {})
    return
  }

  let port = -1
  let server
  let dataVersions = new Map()
  let TestLog = createTestLog()

  const { next } = nextTestSetup({
    files: __dirname,
    skipStart: true,
  })

  beforeAll(async () => {
    port = await findPort()
    server = createTestDataServer(async (key, res) => {
      const currentVersion = dataVersions.get(key)

      // Increment the version number each time to track how often the
      // server renders.
      const nextVers

 ' + key)
      res.resolve(response)
    })
    server.listen(port)

    next.env.TEST_DATA_SERVICE_URL = `http://localhost:${port}`
    await next.start()
  })

  beforeEach(async () => {
    dataVersions = new Map()
    TestLog = createTestLog()
  })

ion = currentVersion === undefined ? 1 : currentVersion + 1
      dataVersions.set(key, nextVersion)

      // Append the version number to the response
      const response = `${key} [${nextVersion}]`
      TestLog.log('REQUEST:


'next/link'
import Form from 'next/form'
import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'

export function LinkAccordion({
  href,
  children,
  prefetch,
}: {
  href: string
  children: React.ReactNode
  prefetch?: LinkProps['prefetch']
}) {
  const [isVisible, setIsVisible] = useState(false)
  return (
    <>
      <input
        type="checkbox"
        checked={isVisible}
        onChange={() => setIsVisible(!isVisible)}
        data-link-accordion={href}
      />

dren,
  prefetch,
}: {
  action: string
  children: React.ReactNode
  prefetch?: null | false
}) {
  const [isVisible, setIsVisible] = useState(false)
  return (
    <>
      <input
        type="checkbox"
        checked={isVisible}
        onChange={() =

     {isVisible ? (
        <Link href={href} prefetch={prefetch}>
          {children}
        </Link>
      ) : (
        <>{children} (link is hidden)</>
      )}
    </>
  )
}

export function FormAccordion({
  action,
  chil


alidatePath, updateTag } from 'next/cache'
import {
  LinkAccordion,
  FormAccordion,
  ManualPrefetchLinkAccordion,
} from '../components/link-accordion'
import Link from 'next/link'

export default async function Page() {
  return (
    <>
      <form>
        <button
          id="revalidate-by-path"
          formAction={async function () {
            'use server'
            revalidatePath('/greeting')
          }}
        >
          Revalidate by path
        </button>
        <button
          id="

          <LinkAccordion href="/greeting">
            Link to target page with prefetching enabled
          </LinkAccordion>

          <FormAccordion action="/greeting">
            Form pointing to target page with prefet

revalidate-by-tag"
          formAction={async function () {
            'use server'
            updateTag('random-greeting')
          }}
        >
          Revalidate by tag
        </button>
      </form>
      <ul>


k-accordion'

export default function RefetchOnNewBaseTreeLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <>

          This demonstrates what happens when a link is prefetched using{' '}
          {'prefetch={true}'} and the URL changes. Next.js should
          re-prefetch the link in case the delta between the base tree and the
          target tree has changed.

etch for
          this link will be empty, because there's no delta between the base
          tree and the target tree.
        </p>
        <p>
          However, if you then navigate to page B, we should re-prefetch the
          link to A, because the

          Everything in this gray section is part of a shared layout. The links
          below are prefetched using <code>{'prefetch={true}'}</code>. If the
          first loaded page is "/refetch-on-new-base-tree/a", the pref


ort { LinkAccordion } from './link-accordion'

export default function Page() {
  return (
    <>

          <LinkAccordion prefetch={true} href="/page-with-dynamic-head">
            Page with dynamic head (prefetch=true)
          </LinkAccordion>

          <LinkAccordion
            prefetch={true}
            href="/rewrite-to-page-with-dynamic-head"
          >
            Rewrite to page with dynamic head (prefetch=true)
          </LinkAccordion>

prefetch=true)
          </LinkAccordion>
        </li>
        <li>
          <LinkAccordion
            prefetch={true}
            href="/rewrite-to-page-with-runtime-prefetchable-head"
          >
            Rewrite to page with runtime-prefetchable h

          <LinkAccordion
            prefetch={true}
            href="/page-with-runtime-prefetchable-head"
          >
            Page with runtime-prefetchable head (


use cache'

import { cacheTag } from 'next/cache'
import { Suspense } from 'react'

const TEST_DATA_SERVICE_URL = process.env.TEST_DATA_SERVICE_URL
const ARTIFICIAL_DELAY = 3000

async function Greeting() {
  cacheTag('random-greeting')
  if (!TEST_DATA_SERVICE_URL) {
    // If environment variable is not set, resolve automatically after a delay.
    // This is so you can run the test app locally without spinning up a
    // data server.
    await new Promise<void>((resolve) =>
      setTimeout(() => resolv

t = await response.text()
  if (response.status !== 200) {
    throw new Error(text)
  }
  return (
    <>

Greeting

{text}

    </>
  )
}

export default async function Page() {
  return (
    <Suspense fallback

e(), ARTIFICIAL_DELAY)
    )
    // Return a random greeting
    return ['Hello', 'Hi', 'Hey', 'Howdy'][Math.floor(Math.random() * 4)]
  }
  const response = await fetch(TEST_DATA_SERVICE_URL + '?key=random-greeting')
  const tex


ort function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/search-params/target-page')) {
    const searchParam = request.nextUrl.searchParams.get('searchParam')
    if (
      searchParam === 'rewritesToANewSearchParam' ||
      searchParam === 'alsoRewritesToThatSameSearchParam'
    ) {
      return NextResponse.rewrite(
        new URL(
          '/search-params/target-page?searchParam=rewrittenSearchParam',
          request.url
        )
      )
    }
  }

  if (request

eeting')) {
    return NextResponse.rewrite(
      new URL('/search-params?greeting=hello', request.url)
    )
  }

  if (request.nextUrl.pathname.startsWith('/search-params-with-no-greeting')) {
    return NextResponse.rewrite(new URL('/search-params', re


createRouterAct } from 'router-act'

describe('segment cache (search params shared loading state)', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })
  if (isNextDev) {
    test('prefetching is disabled', () => {})
    return
  }

  it(
    "if there's no matching prefetch entry for a page with particulular " +
      'search params, optimistically reuse a prefetch entry with the same ' +
      'pathname and different search params',
    async () => {
      let act: ReturnType<

     // Reveal and prefetch the link without search params
      const revealFirstLink = await browser.elementByCss(
        'input[data-link-accordion="/search-params-shared-loading-state/target-page"]'
      )
      await act(
        async () => {

typeof createRouterAct>
      const browser = await next.browser(
        '/search-params-shared-loading-state',
        {
          beforePageLoad(page) {
            act = createRouterAct(page)
          },
        }
      )


arams in the cache key', async () => {
    let act: ReturnType<typeof createRouterAct>
    const browser = await next.browser('/search-params', {
      beforePageLoad(page) {
        act = createRouterAct(page)
      },
    })

    // Prefetch a page with search param `a_PPR`.
    const revealA = await browser.elementByCss(
      'input[data-link-accordion="/search-params/target-page?searchParam=a_PPR"]'
    )
    await act(
      async () => {
        await revealA.click()
      },
      // The response wi

   // Prefetch the same page but with the search param changed to `c_PPR`.
    const revealC = await browser.elementByCss(
      'input[data-link-accordion="/search-params/target-page?searchParam=c_PPR"]'
    )
    await act(
      async () => {
        aw

ll include a shell of the page, but nothing that is
      // based on the search param.
      {
        includes:
          // This is the id assigned to a container div
          'target-page-with-search-param',
      }
    )


rt default function SearchParamsPage({
  searchParams,
}: {
  searchParams: Promise<{ greeting?: string }>
}) {
  return (
    <>

        Demonstrates that we can prefetch a page that reads from search params

          <LinkAccordion href="/search-params/target-page?searchParam=a_PPR">
            searchParam=a_PPR
          </LinkAccordion>

          <LinkAccordion
            prefetch={true}
            href="/search-params/target-pag

rchParam=c_PPR
          </LinkAccordion>
        </li>
        <li>
          <LinkAccordion
            prefetch={true}
            href="/search-params/target-page?searchParam=d_full"
          >
            searchParam=d_full, prefetch={true}

e?searchParam=b_full"
          >
            searchParam=b_full, prefetch={true}
          </LinkAccordion>
        </li>
        <li>
          <LinkAccordion href="/search-params/target-page?searchParam=c_PPR">
            sea


 {import('next').NextConfig}
 */
const nextConfig = {
  cacheComponents: true,
  experimental: {
    optimisticRouting: true,
    varyParams: true,
  },
  // Each rewrite below crafts one of the rewrite-affected response shapes
  // we want to verify. They live in `beforeFiles` so they take precedence
  // over the filesystem dynamic route — otherwise a 1-part URL like
  // /featured would route directly to the filesystem (matched by the
  // dynamic /[teamSlug]) without going through the rewrite, and we'd

hrough the dynamic /[teamSlug] route.
        { source: '/featured', destination: '/some-team' },
        // Case "static-visible-null": URL is shorter than the response,
        // and the deeper segment is a visible static segment.
        { source: '/te

  // never observe the rewrite-affected response shape under test.
  async rewrites() {
    return {
      beforeFiles: [
        // Case "static-sibling": URL matches a known static sibling, but
        // the rewrite sends it t


'

describe('optimistic routing - rewrite detection regression', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  if (isNextDev) {
    // Optimistic routing is a production-build feature; in dev mode the
    // router does not have complete information about which routes
    // exist, so prediction is disabled.
    test('skipped in dev mode', () => {})
    return
  }

  // The shape of every test below is the same:
  //
  // 1. Reveal a "prefetch" link whose URL arrives vi

 URLs of the same dynamic shape would receive an incorrect
  //    "free" prediction and could render a stale loading state
  //    instantly.
  // 2. Reveal one of the click-target links (prefetch={false}).
  // 3. Click it inside an act scope. With the b

a a rewrite. The
  //    response describes a route shape the URL would not naturally
  //    route to. The router must not learn from this response as a
  //    prediction template — otherwise future navigations to other
  //


kAccordion } from '../components/link-accordion'

export default function Home() {
  return (

HOME

        {/* The four prefetch URLs below each arrive via a rewrite that
            produces a route shape the URL would not naturally route to.
            Each test reveals one of them (default prefetch=true) to
            populate the router's prediction state, then clicks one of
            the click-targets below to check that no incorrect prediction
            was l

          <LinkAccordion href="/team-shorter">
            Static-visible-null
          </LinkAccordion>
        </li>

        {/* Click target — prefetch={false} so revealing it fires no
            request. Inside an act scope, the test clicks this and

earned. */}

          <LinkAccordion href="/myteam/garbage">Tree-shorter</LinkAccordion>

          <LinkAccordion href="/featured">Static-sibling</LinkAccordion>


uspense } from 'react'
import { connection } from 'next/server'

async function DynamicOverview({
  params,
}: {
  params: Promise<{ teamSlug: string }>
}) {
  await connection()
  const { teamSlug } = await params
  return (
    <h1 id="overview-page" data-slug={teamSlug}>
      Overview: {teamSlug}
    </h1>
  )
}

// Static visible deeper segment. Used by the static-visible-null test:
// the rewrite /team-shorter → /team-shorter/overview produces a response
// that walks through this segment with no URL

t.
export default function OverviewPage({
  params,
}: {
  params: Promise<{ teamSlug: string }>
}) {
  return (

      <Suspense fallback={
Loading team...
}>
        <DynamicOverview params={params} />
      </Suspens


from 'e2e-utils'
import type * as Playwright from 'playwright'
import { createRouterAct } from 'router-act'

describe('dynamic on hover', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })
  if (isNextDev) {
    test('prefetching is disabled', () => {})
    return
  }

  it('prefetches the dynamic data for a Link on hover', async () => {
    let act: ReturnType<typeof createRouterAct>
    const browser = await next.browser('/', {
      beforePageLoad(p: Playwright.Page) {

Reveal the link to start prefetching. Since the link has not been hovered
    // yet, the prefetch only includes static data.
    await act(async () => {
      await linkVisibilityToggle.click()
      await browser.elementByCss('a[href="/dynamic"]')
    },

   act = createRouterAct(p)
      },
    })

    // This Link's unstable_dynamicOnHover prop is set to true
    const linkVisibilityToggle = await browser.elementByCss(
      'input[data-link-accordion="/dynamic"]'
    )

    //


inkProps } from 'next/link'
import { useState } from 'react'

export function LinkAccordion({
  href,
  children,
  prefetch,
  unstable_dynamicOnHover,
}: {
  href: string
  children: React.ReactNode
  prefetch?: LinkProps['prefetch']
  unstable_dynamicOnHover?: boolean
}) {
  const [isVisible, setIsVisible] = useState(false)
  return (
    <>
      <input
        type="checkbox"
        checked={isVisible}
        onChange={() => setIsVisible(!isVisible)}
        data-link-accordion={href}
      />

         prefetch={prefetch}
          // @ts-expect-error - unstable_dynamicOnHover is not part of the public types
          unstable_dynamicOnHover={unstable_dynamicOnHover}
        >
          {children}
        </Link>
      ) : (
        <>{children}

{isVisible ? (
        <Link
          href={href}


from 'e2e-utils'
import { retry } from 'next-test-utils'

describe('segment cache - stale search params on replace regression', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  if (isNextDev) {
    test('skipped in dev mode', () => {})
    return
  }

  // Regression test for https://github.com/vercel/next.js/issues/91658.
  //
  // Reproduction is taken directly from the user's report and from their
  // minimal repro at https://github.com/dlehmhus/next-router-replace-bug

ge-2">` — navigates to /dummy-page-2.
  // 5. Click the button that calls `router.replace('/')`.
  //
  // Expected: URL is `/` with no search string.
  // Buggy:   URL becomes `/?query=param` — the search string from the
  //          original page load i

:
  //
  // 1. Build and start the application.
  // 2. Open `/?query=param` directly in the browser (full page load).
  // 3. Click `<Link href="/dummy-page-1">` — navigates to /dummy-page-1.
  // 4. Click `<Link href="/dummy-pa


eRouterAct } from 'router-act'

describe('force stale', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })
  if (isNextDev) {
    test('prefetching is disabled in dev', () => {})
    return
  }

  it(
    'during a navigation, don\'t request segments that have a pending "full" ' +
      'prefetch already in progress',
    async () => {
      let act: ReturnType<typeof createRouterAct>
      const browser = await next.browser('/', {
        beforePageLoad(p: Playwright.Page) {

 dynamic content.
          const toggleLinkVisibility = await browser.elementByCss(
            'input[data-link-accordion="/dynamic"]'
          )
          await act(async () => await toggleLinkVisibility.click(), {
            includes: 'Dynamic page c

         act = createRouterAct(p)
        },
      })

      await act(
        async () => {
          // Reveal a link to a dynamic page. The Link has prefetch={true}, so the
          // full page data is prefetched, including


t { nextTestSetup } from 'e2e-utils'
import { createRouterAct } from 'router-act'

describe('prefetch inlining without cacheComponents', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  if (isNextDev) {
    it('prefetch hints are only computed during build', () => {})
    return
  }

  it('static page is prefetched with inlining', async () => {
    // Static pages always have hints computed during the build, regardless
    // of cacheComponents. Inlining should work normal

{
        await browser
          .elementByCss('input[data-link-accordion="/static-page"]')
          .click()
      },
      { includes: 'Static page' }
    )

    await act(async () => {
      await browser.elementByCss('a[href="/static-page"]').click()

ly.
    let page: Playwright.Page
    const browser = await next.browser('/', {
      beforePageLoad(p: Playwright.Page) {
        page = p
      },
    })
    const act = createRouterAct(page!)

    await act(
      async () =>