Link from 'next/link'
import { useRouter } from 'next/router'
import React from 'react'

const LongPageToSnapScroll = () => {
  const router = useRouter()
  return (

      <Link href="#item-400" id="scroll-to-item-400">
        Go to item 400
      </Link>

      {Array.from({ length: 500 }, (x, i) => i + 1).map((i) => {
        return (
          <div key={`item-${i}`} id={`item-${i}`}>
            {i}

        )
      })}

      <Link href="/snap-sc

er.push('/snap-scroll-position')
        }}
      >
        Go to snap scroll imperative
      </div>
      <div
        id="goto-snap-scroll-position-imperative-noscroll"
        onClick={(e) => {
          e.preventDefault()
          router.push('/snap-

roll-position" id="goto-snap-scroll-position">
        Go to snap scroll declarative
      </Link>
      <div
        id="goto-snap-scroll-position-imperative"
        onClick={(e) => {
          e.preventDefault()
          rout


mport { Component } from 'react'
import Link from 'next/link'

export default class OnClick extends Component {
  static getInitialProps({ res, query: { count } }) {
    return { count: count ? parseInt(count) : 0 }
  }

  state = {
    stateCounter: 0,
  }

  render() {
    const { stateCounter } = this.state
    const { count } = this.props
    return (
      <div id="on-click-page">
        <Link
          href={`/nav/on-click?count=${count + 1}`}
          replace
          id="on-click-link"

{
            e.preventDefault()
            this.setState({ stateCounter: stateCounter + 1 })
          }}
        >
          Self Reload
        </Link>

QUERY COUNT: {count}

STATE COUNT: {stat

onClick={() => this.setState({ stateCounter: stateCounter + 1 })}
        >
          Self Reload
        </Link>
        <Link
          href="/nav/on-click"
          id="on-click-link-prevent-default"
          onClick={(e) =>


 Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'

export default function Page() {
  const router = useRouter()

  const [routeState, setRouteResult] = useState({
    completed: 0,
    errors: 0,
  })
  useEffect(() => {
    const increaseErrorCount = () =>
      setRouteResult((state) => ({ ...state, errors: state.errors + 1 }))
    const increaseRouteComplete = () =>
      setRouteResult((state) => ({ ...state, completed: state.completed + 1 }))

.off('routeChangeComplete', increaseRouteComplete)
    }
  })

  return (
    <>

{JSON.stringify(routeState)}

      <Link href="?prop=foo" id="link" shallow={true}>
        Click me
      </Link>
      <button
        id="r

  router.events.on('routeChangeError', increaseErrorCount)
    router.events.on('routeChangeComplete', increaseRouteComplete)

    return () => {
      router.events.off('routeChangeError', increaseErrorCount)
      router.events


ter'

export default function Page() {
  const router = useRouter()
  return (
    <>
      <button
        id="click-me"
        onClick={() =>
          router.push({
            pathname: '/query',
            query: {
              param1: '',
              param2: undefined,
              param3: null,
              param4: 0,
              param5: false,
              param6: [],
              param7: {},
              param8: NaN,
              param9: new Date(1234),
              param10: /hello/,

         undefined,
                null,
                0,
                false,
                [],
                {},
                NaN,
                new Date(1234),
                /hello/,
              ],
            },
          })
        }


 'react'
import Link from 'next/link'
import Router, { withRouter } from 'next/router'

let getInitialPropsRunCount = 1

const linkStyle = {
  marginRight: 10,
}

export default withRouter(
  class extends Component {
    static getInitialProps({ res }) {
      if (res) return { getInitialPropsRunCount: 1 }
      getInitialPropsRunCount++

      return { getInitialPropsRunCount }
    }

    getCurrentCounter() {
      const { router } = this.props
      return router.query.counter ? parseInt(router.query.co

NonShallow() {
      const counter = this.getCurrentCounter()
      const href = `/nav/shallow-routing?counter=${counter + 1}`
      Router.push(href, href, {})
    }

    gotoNavShallow() {
      const href = `/nav`
      Router.push(href, href, { shallow

unter) : 0
    }

    increase(scroll) {
      const counter = this.getCurrentCounter()
      const href = `/nav/shallow-routing?counter=${counter + 1}`
      Router.push(href, href, { shallow: true, scroll })
    }

    increase


 expect(stripAnsi(next.cliOutput)).toContain(
        isTurbopack
          ? '\n⨯ Error: boom' +
              // TODO(veil): Sourcemap to original name i.e. "default"
              '\n    at __TURBOPACK__default__export__ (middleware.js:3:15)' +
              '\n  1 |'
          : isRspack
            ? '\n⨯ Error: boom' +
              '\n    at __rspack_default_export (middleware.js:3:15)' +
              '\n  1 |'
            : '\n⨯ Error: boom' +
              '\n    at default (middleware.js:3:15)' +

correctly and recovers', async () => {
      const browser = await next.browser('/')

      if (isTurbopack) {
        await expect(browser).toDisplayRedbox(`
         {
           "code": "E394",
           "description": "boom",
           "environmentLa

              '\n  1 |'
      )
      expect(stripAnsi(next.cliOutput)).toContain(
        '' +
          "\n> 3 |         throw new Error('boom')" +
          '\n    |               ^'
      )
    })

    it('renders the error


tSetup } from 'e2e-utils'
import { join } from 'path'
import {
  waitForRedbox,
  waitForNoRedbox,
  getRedboxSource,
} from 'next-test-utils'

// TODO: The error overlay is not closed when restoring the working code.
describe.skip('next/font build-errors', () => {
  const { next } = nextTestSetup({
    files: new FileRef(join(__dirname, 'build-errors')),
  })

  it('should show a next/font error when input is wrong', async () => {
    const browser = await next.browser('/')
    const content = await next.r

!</p>
}
`
    )

    await waitForRedbox(browser)
    expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
      "app/page.js
      \`next/font\` error:
      Missing required \`src\` property"
    `)

    await next.patchFile('app/page.js', cont

eadFile('app/page.js')

    await next.patchFile(
      'app/page.js',
      `
import localFont from 'next/font/local'

const font = localFont()

export default function Page() {
  return <p className={font.className}>Hello world


int-env jest */
import { nextTestSetup } from 'e2e-utils'
import { check } from 'next-test-utils'

describe('Deprecated @next/font warning', () => {
  const { next, skipped } = nextTestSetup({
    files: {
      'pages/index.js': '',
    },
    dependencies: {
      '@next/font': 'canary',
    },
    skipStart: true,
  })
  if (skipped) return

  it('should warn if @next/font is in deps', async () => {
    await next.start()
    await check(() => next.cliOutput, /ready/i)
    await check(
      () => next.c

deps
    const packageJson = JSON.parse(await next.readFile('package.json'))
    delete packageJson.dependencies['@next/font']
    await next.patchFile('package.json', JSON.stringify(packageJson))

    await next.start()
    await check(() => next.cliOutpu

liOutput,
      new RegExp('please use the built-in `next/font` instead')
    )

    await next.stop()
    await next.clean()
  })

  it('should not warn if @next/font is not in deps', async () => {
    // Remove @next/font from


 { FileRef, nextTestSetup } from 'e2e-utils'
import { waitForRedbox, getRedboxSource } from 'next-test-utils'
import { join } from 'path'

describe('font-loader-in-document-error', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'font-loader-in-document/pages')),
    },
  })

  test('next/font inside _document', async () => {
    const browser = await next.browser('/')
    await waitForRedbox(browser)
    if (process.env.IS_TURBOPACK_TEST) {
      // TODO: Tu

.NEXT_RSPACK) {
      expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
       "pages/_document.js
         × \`next/font\` error:
         │ Cannot be used within pages/_document.js."
      `)
    } else {
      expect(await getRedboxSource(b

rbopack doesn't include pages/
      expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
        "./_document.js
        next/font: error:
        Cannot be used within _document.js"
      `)
    } else if (process.env


 join } from 'path'
import fs from 'fs-extra'

describe('jsconfig-path-reloading', () => {
  const tsConfigFile = 'jsconfig.json'
  const indexPage = 'pages/index.js'

  const tsConfigContent = fs.readFileSync(
    join(__dirname, 'app/jsconfig.json'),
    'utf8'
  )

  function runTests({ addAfterStart }: { addAfterStart?: boolean }) {
    const { next } = nextTestSetup({
      files: {
        components: new FileRef(join(__dirname, 'app/components')),
        pages: new FileRef(join(__dirname, 'app/pages

latest',
        '@types/react': 'latest',
        '@types/node': 'latest',
      },
    })

    if (addAfterStart) {
      beforeAll(async () => {
        await next.patchFile(tsConfigFile, tsConfigContent)
      })
    }

    it('should load with initial

')),
        lib: new FileRef(join(__dirname, 'app/lib')),
        ...(addAfterStart
          ? {}
          : {
              [tsConfigFile]: tsConfigContent,
            }),
      },
      dependencies: {
        typescript: '


c function getStaticProps() {
        return {
         props: { posts: ["my isr post"] },
         revalidate: 10,
        }
       }`

const blogGspRevalidateFalse = `export default function Blog({ posts }) {
        return posts.map(p => (
{p}
))
       }

       export async function getStaticProps() {
        return {
         props: { posts: ["my gsp post"] },
         revalidate: false,
        }
       }`

const blogGspNoRevalidate = `export default function Blog({ posts }) {

on Blog({ posts }) {
        return posts.map(p => (
{p}
))
       }

       export async function getServerSideProps() {
         return {
           props: { posts: ["my ssr post"] },
         }
       }`

const postsSlug = (fallback: st

return posts.map(p => (
{p}
))
       }

       export async function getStaticProps() {
        return {
         props: { posts: ["my gsp post"] },
        }
       }`

const blogGssp = `export default functi


ort { join } from 'path'
import { FileRef, nextTestSetup } from 'e2e-utils'
import { shouldUseTurbopack } from 'next-test-utils'

describe('typescript-external-dir', () => {
  const { next } = nextTestSetup({
    files: {
      project: new FileRef(join(__dirname, 'project')),
      shared: new FileRef(join(__dirname, 'shared')),
    },
    // Run Next.js from inside `project/` so its `tsconfig.json` `paths`
    // resolve correctly. `shared/` is a sibling at the install root, which
    // contains the lock

 dev${
          shouldUseTurbopack() ? ' --turbopack' : ''
        }`,
      },
    },
    startCommand: 'pnpm run dev-project',
  })

  it('should render the page with external TS/TSX dependencies', async () => {
    const $ = await next.render$('/')

file, so Turbopack's `rootPath` includes both
    // directories and `experimental.externalDir` resolves
    // `../../shared/*` from `project/pages`.
    packageJson: {
      scripts: {
        'dev-project': `cd project && next


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

describe('stale-dev-types', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not fail build when .next/dev has stale types from deleted routes', async () => {
    // Step 1: Wait for dev server to generate .next/dev/types/validator.ts
    await retry(
      async () => {
        const exists = await next
          .readFile('.next/dev/types/validator.ts')
          .then(() => true)
          .catch(() => false)

eadFile('.next/dev/types/validator.ts')
    expect(validatorContent).toContain('temp-route/page')

    // Step 2: Stop dev server
    await next.stop()

    // Step 3: Delete the temp-route (simulating user deleting a route)
    await next.deleteFile('app/

     if (!exists) {
          throw new Error('validator.ts not generated yet')
        }
      },
      5000,
      500
    )

    // Verify validator.ts contains reference to temp-route
    const validatorContent = await next.r


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

describe('Dynamic route rename casing', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not throw error when changing casing of dynamic route file', async () => {
    const html = await next.render('/abc')
    expect(html).toContain('hi')

    await next.renameFile('pages/[pid].js', 'pages/[PiD].js')

    await retry(async () => {
      expect(next.cliOutput).not.toContain(
        `You cannot use di

ames for the same dynamic path`
      )
    })

    await next.renameFile('pages/[PiD].js', 'pages/[pid].js')

    await retry(async () => {
      expect(next.cliOutput).not.toContain(
        `You cannot use different slug names for the same dynamic path`


e('spaces', () => {
    it('should have correct query on SSR', async () => {
      const browser = await next.browser(encodeURI('/single/hello world '))
      const text = await browser.elementByCss('#query-content').text()
      expect(text).toMatchInlineSnapshot(`"{"slug":"hello world "}"`)
    })

    it('should have correct query on Router#push', async () => {
      const browser = await next.browser('/')
      await browser.eval(
        `window.next.router.push(
          { pathname: '/single/[slug]'

 const text = await browser.elementByCss('#query-content').text()
      expect(text).toMatchInlineSnapshot(`"{"slug":"hello world "}"`)
    })

    it('should have correct query on simple client-side <Link>', async () => {
      const browser = await next.

},
          { pathname: encodeURI('/single/hello world ') }
        )`
      )
      await retry(async () => {
        expect(await browser.hasElementByCssSelector('#query-content')).toBe(
          true
        )
      })


import Link from 'next/link'

const Home = () => (

    <Link
      href="/single/[slug]"
      as={encodeURI('/single/hello world ')}
      id="single-spaces"
    >
      Single: Spaces
    </Link>

    <Link
      href="/single/[slug]"
      as={encodeURI('/single/hello%world')}
      id="single-percent"
    >
      Single: Percent
    </Link>

    <Link
      href="/single/[slug]"
      as={`/single/hello${encodeURIComponent('/')}world`}
      id="single-slash"
    >
      Sing

href="/single/[slug]"
      as={`/single/hello${encodeURIComponent(':')}world`}
      id="single-colon"
    >
      Single: :
    </Link>
    <br />
    <Link href="/query?id=http://example.com/" id="url-param">
      Url query param
    </Link>
  </div>
)

le: Forward Slash
    </Link>

    <Link
      href="/single/[slug]"
      as={`/single/hello${encodeURIComponent('"')}world`}
      id="single-double-quote"
    >
      Single: "
    </Link>

    <Link


mport { nextTestSetup } from 'e2e-utils'

describe('Configuration with next.config.mjs', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should disable X-Powered-By header support', async () => {
    const res = await next.fetch('/')
    expect(res.headers.get('X-Powered-By')).not.toBe('Next.js')
  })

  it('correctly imports a package that defines `module` but no `main` in package.json', async () => {
    const $ = await next.render$('/module-only-content')
    expect($('#messa

.text()).toBe('OK')
  })

  it('should have env variables available on the client', async () => {
    const browser = await next.browser('/next-config')
    const envValue = await browser.elementByCss('#env').text()
    expect(envValue).toBe('hello')
  })


tTestSetup } from 'e2e-utils'
import { fetchViaHTTP } from 'next-test-utils'
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'Slow Module Detection',
  () => {
    const { next } = nextTestSetup({
      files: __dirname,
      overrideFiles: {
        'utils/slow-module.js': `
          // This module is intentionally made complex to trigger slow compilation
          ${Array(2000)
            .fill(0)
            .map(
              (_, i) => `
              export const value${i} = ${JSON.s

ync () => {
      let logs = ''
      next.on('stdout', (log) => {
        logs += log
      })

      // Trigger a compilation by making a request
      await fetchViaHTTP(next.url, '/')

      // Wait for compilation to complete and check logs
      awai

tringify(
                Array(100).fill(`some-long-string-${i}`).join('')
              )}
            `
            )
            .join('\n')}
        `,
      },
    })

    it('should detect slow modules in webpack mode', as


ort { nextTestSetup } from 'e2e-utils'
import { fetchViaHTTP } from 'next-test-utils'

describe('Rewritten API Requests should pass OPTIONS requests to the api function', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/api/some-endpoint.js': `
        export default (req, res) => {
          res.end("successfully hit some-endpoint!")
        }
      `,
    },
    nextConfig: {
      rewrites: () =>
        Promise.resolve({
          beforeFiles: [
            // Nextjs by default requ

ependencies: {},
  })

  it('should pass OPTIONS requests to the api function', async () => {
    const res = await fetchViaHTTP(next.url, '/some-endpoint', null, {
      method: 'OPTIONS',
      headers: {
        Origin: 'http://localhost:3000',
      },

ires a /api prefix, let's remove that
            {
              source: '/:path*',
              destination: '/api/:path*',
            },
          ],
          afterFiles: [],
          fallback: [],
        }),
    },
    d


rollHandlerNew'
  : 'InnerScrollAndFocusHandlerOld'

function setupLogCapture() {
  const logs: string[] = []
  const originalStdout = process.stdout.write
  const originalStderr = process.stderr.write

  const capture = (chunk: any) => {
    logs.push(stripAnsi(chunk.toString()))
    return true
  }

  process.stdout.write = function (chunk: any) {
    capture(chunk)
    return originalStdout.call(this, chunk)
  }

  process.stderr.write = function (chunk: any) {
    capture(chunk)
    return originalStder

}
}

describe(`Terminal Logging (${bundlerName})`, () => {
  describe('Pages Router', () => {
    let logs: string[] = []
    let logCapture: ReturnType<typeof setupLogCapture>
    let browser = null

    beforeAll(() => {
      logCapture = setupLogCaptur

r.call(this, chunk)
  }

  const restore = () => {
    process.stdout.write = originalStdout
    process.stderr.write = originalStderr
  }

  const clearLogs = () => {
    logs.length = 0
  }

  return { logs, restore, clearLogs


import { nextTestSetup } from 'e2e-utils'

describe('experimental-https-server OpenGraph image', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    startCommand: 'pnpm next dev --experimental-https',
    skipStart: !process.env.NEXT_TEST_CI,
  })
  if (skipped) return

  if (!process.env.NEXT_TEST_CI) {
    console.warn('only runs on CI as it requires administrator privileges')
    it('only runs on CI as it requires administrator privileges', () => {})
    return
  }

  it('should

onst html = await browser.eval('document.documentElement.innerHTML')
    expect(html).toContain('Hello from App')
    expect(html).toMatch(/<meta property="og:image" content="https:\/\//)
    expect(html).toMatch(/<meta name="twitter:image" content="https:

 generate https:// URLs for OpenGraph images when experimental HTTPS is enabled', async () => {
    expect(next.url).toContain('https://')
    const browser = await next.browser('/1', {
      ignoreHTTPSErrors: true,
    })
    c


tTestSetup } from 'e2e-utils'
import https from 'https'
import { renderViaHTTP } from 'next-test-utils'

describe('experimental-https-server (generated certificate)', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    startCommand: 'pnpm next dev --experimental-https',
    skipStart: !process.env.NEXT_TEST_CI,
  })
  if (skipped) return

  if (!process.env.NEXT_TEST_CI) {
    console.warn('only runs on CI as it requires administrator privileges')
    it('only runs on CI as it requ

tps://')
    const html = await renderViaHTTP(next.url, '/1', undefined, { agent })
    expect(html).toContain('Hello from App')
  })

  it('should successfully load the app in pages dir', async () => {
    expect(next.url).toInclude('https://')
    const

ires administrator privileges', () => {})
    return
  }

  const agent = new https.Agent({
    rejectUnauthorized: false,
  })

  it('should successfully load the app in app dir', async () => {
    expect(next.url).toInclude('ht


port { renderViaHTTP } from 'next-test-utils'

describe('experimental-https-server (provided certificate)', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    startCommand: `pnpm next dev --experimental-https --experimental-https-key ./certificates/localhost-key.pem --experimental-https-cert ./certificates/localhost.pem`,
  })
  const agent = new https.Agent({
    rejectUnauthorized: false,
  })

  it('should successfully load the app in app dir', async () => {
    expect(next.url).toInclu

next.url, '/1', undefined, { agent })
    expect(html).toContain('Hello from App')
  })

  it('should successfully load the app in pages dir', async () => {
    expect(next.url).toInclude('https://')
    const html = await renderViaHTTP(next.url, '/2', und


from 'e2e-utils'
import { retry, shouldUseTurbopack, waitFor } from 'next-test-utils'
;(shouldUseTurbopack() ? describe.skip : describe)('On Demand Entries', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    startCommand: 'node server.js',
    serverReadyPattern: /- Local:/,
    dependencies: {
      'get-port': '5.1.1',
    },
  })

  it('should compile pages for SSR', async () => {
    const pageContent = await next.render('/')
    expect(pageContent).toContain('Index Page')
  })

  it(

/about']
    expect(pageFiles).toBeDefined()
    const pageFile = pageFiles[pageFiles.length - 1]
    expect(pageFile).toMatch(/\.js$/)
    expect(pageFile).toContain('pages/about')
    const pageContent = await next.render(`/_next/${pageFile}`)
    expect

'should compile pages for JSON page requests', async () => {
    await next.render('/about')
    const manifest = JSON.parse(
      await next.readFile('.next/dev/build-manifest.json')
    )
    const pageFiles = manifest.pages['


test-utils'

describe('getServerSideProps redirects', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should use a client-side navigation for a rewritten URL', async () => {
    const browser = await next.browser('/alias-to-main-content')

    await browser.eval('window.__SAME_PAGE = true')
    await browser.elementByCss('#link-with-rewritten-url').click()
    await browser.waitForElementByCss('.refreshed')

    expect(await browser.eval('window.__SAME_PAGE')).toBe(true)
  })

known URL', async () => {
    const browser = await next.browser('/alias-to-main-content')

    await browser.eval('window.__SAME_PAGE = true')
    await browser.elementByCss('#link-unknown-url').click()

    await retry(async () => {
      const val = awa

it('should fallback to browser navigation for an un


ssage }) {
  return (

Hello {message}

          <Link
            href="/redirector?redirect=/alias-to-main-content&message=refreshed"
            id="link-with-rewritten-url"
            className={message}
          >
            Link with rewritten target url
          </Link>

          <Link href="/redirector?redirect=/main-content&message=refreshWithClientSideNavigation">
            Link with client side navigation

k
            href="/redirector?redirect=/unknown-route"
            id="link-unknown-url"
          >
            Link to unknown internal navigation
          </Link>
        </li>
      </ul>
    </main>
  )
}

export const getServerSideProps = ({ query

  </Link>
        </li>

        <li>
          <Lin


y from 'next'
import ts from 'typescript'
export { NEXT_TS_ERRORS } from 'next/dist/server/typescript/constant'

export type PluginLanguageService = ts.LanguageService & {
  getCapturedLogs: () => string
}

export function getPluginLanguageService(dir: string): PluginLanguageService {
  const files = ts.sys.readDirectory(dir)

  const compilerOptions = ts.getDefaultCompilerOptions()
  const compilerHost = ts.createCompilerHost(compilerOptions)

  let logs = ''
  const logger = {
    info: (...args: any[]) =

nguageServiceHost = {
    ...compilerHost,
    getCompilationSettings: () => compilerOptions,
    getScriptFileNames: () => files,
    getScriptSnapshot: (fileName) => {
      const contents = ts.sys.readFile(fileName)
      if (contents && typeof contents

> {
      const message = args
        .map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))
        .join(' ')
      logs += message + '\n'
      console.log(...args)
    },
  }

  const languageServiceHost: ts.La


tsFiles) {
      // This test expects no diagnostics, but if somehow the test
      // detects one and fails, the diagnostics output on the terminal
      // is too long and omits the filename, so we filter out only the
      // necessary properties for debugging.
      totalDiagnostics[relative(__dirname, tsFile)] = languageService
        .getSemanticDiagnostics(tsFile)
        .map((diagnostic) => ({
          code: diagnostic.code,
          messageText: diagnostic.messageText,
          start: diagnost

warn-no-type/metadata/has-type/export-inline-from-next/page.tsx": [],
       "app/warn-no-type/metadata/has-type/export-inline-from-other/layout.tsx": [],
       "app/warn-no-type/metadata/has-type/export-inline-from-other/page.tsx": [],
       "app/warn-n

ic.start,
          length: diagnostic.length,
        }))
    }

    expect(totalDiagnostics).toMatchInlineSnapshot(
      `
     {
       "app/warn-no-type/metadata/has-type/export-inline-from-next/layout.tsx": [],
       "app/


ive, resolve } from 'node:path'
import { getPluginLanguageService } from '../test-utils'

type PartialDiagnostic = Pick<
  ts.Diagnostic,
  'code' | 'messageText' | 'start' | 'length'
>

describe('typescript-plugin - client-boundary', () => {
  let languageService: PluginLanguageService

  beforeAll(() => {
    languageService = getPluginLanguageService(__dirname)
  })

  it('should not have diagnostics for serializable props', () => {
    const tsFile = resolve(__dirname, 'app/serializable-props.tsx')

the filename, so we filter out only the
    // necessary properties for debugging.
    totalDiagnostics[relative(__dirname, tsFile)] = languageService
      .getSemanticDiagnostics(tsFile)
      .map((diagnostic) => ({
        code: diagnostic.code,

const totalDiagnostics: Record<string, PartialDiagnostic[]> = {}

    // This test expects no diagnostics, but if somehow the test
    // detects one and fails, the diagnostics output on the terminal
    // is too long and omits


eca from 'execa'
import fs from 'fs'
import path from 'path'
import stripAnsi from 'strip-ansi'

describe('lockfile', () => {
  const { next, isTurbopack, isRspack } = nextTestSetup({
    files: __dirname,
  })

  it('only allows a single instance of `next dev` to run at a time', async () => {
    const browser = await next.browser('/')
    expect(await browser.elementByCss('p').text()).toBe('Page')

    // Verify lockfile was created with server info inside it
    // With isolatedDevBuild (default), distDi

   const serverInfo = JSON.parse(fs.readFileSync(lockfilePath, 'utf-8'))
    expect(serverInfo).toMatchObject({
      pid: expect.any(Number),
      port: expect.any(Number),
      hostname: expect.any(String),
      appUrl: expect.any(String),
      start

r is .next/dev
    const distDir = path.join(next.testDir, '.next', 'dev')
    const lockfilePath = path.join(distDir, 'lock')
    expect(fs.existsSync(lockfilePath)).toBe(true)

    // Read server info from the lockfile itself


y } from 'next-test-utils'

describe('Client navigation with onClick action', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  it('should reload the page and perform additional action', async () => {
    const browser = await next.browser('/nav/on-click')
    const defaultCountQuery = await browser.elementByCss('#query-count').text()
    const defaultCountState = await browser.elementByCss('#state-coun

fterClicked = await browser
        .elementByCss('#query-count')
        .text()
      const countStateAfterClicked = await browser
        .elementByCss('#state-count')
        .text()
      expect(countQueryAfterClicked).toBe('QUERY COUNT: 1')
      exp

t').text()
    expect(defaultCountQuery).toBe('QUERY COUNT: 0')
    expect(defaultCountState).toBe('STATE COUNT: 0')

    await browser.elementByCss('#on-click-link').click()

    await retry(async () => {
      const countQueryA


rname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  function render(
    pathname: Parameters<typeof renderViaHTTP>[1],
    query?: Parameters<typeof renderViaHTTP>[2]
  ) {
    return renderViaHTTP(next.appPort, pathname, query)
  }

  function fetch(
    pathname: Parameters<typeof renderViaHTTP>[1],
    query?: Parameters<typeof renderViaHTTP>[2]
  ) {
    return fetchViaHTTP(next.appPort, pathname, query)
  }

  async function get$(path: any, query?: any) {
    const

.toContain('<meta charSet="utf-8" data-next-head=""/>')
      expect(html).toContain('My component!')
    })

    it('should should not contain scripts that are not js', async () => {
      const $ = await get$('/')
      $('script[src]').each((_index, ele

html = await render(path, query)
    return cheerio.load(html)
  }

  describe('Rendering via HTTP', () => {
    test('renders a stateless component', async () => {
      const html = await render('/stateless')
      expect(html)


 { nextTestSetup } from 'e2e-utils'

describe('Client navigation with shallow routing', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  it('should update the url without running getInitialProps', async () => {
    const browser = await next.browser('/nav/shallow-routing')
    await browser
      .elementByCss('#increase')
      .click()
      .elementByCss('#increase')
      .click()

    await retry(

t')
      .text()
    expect(getInitialPropsRunCount).toBe('getInitialProps run count: 1')

    await browser.close()
  })

  it('should handle the back button and should not run getInitialProps', async () => {
    const browser = await next.browser('/nav/

async () => {
      const counter = await browser.elementByCss('#counter').text()
      expect(counter).toBe('Counter: 2')
    })

    const getInitialPropsRunCount = await browser
      .elementByCss('#get-initial-props-run-coun


nk'
import { useRouter } from 'next/router'

export async function getServerSideProps({ query: { port } }) {
  if (!port) {
    throw new Error('port required')
  }
  return { props: { port } }
}

export default function Page({ port }) {
  const router = useRouter()
  const [hover, setHover] = React.useState(false)

  return (
    <>
      <Link href="https://vercel.com/" id="absolute-link">
        https://vercel.com/
      </Link>
      <br />
      <button
        id="router-push"
        onClick={() =>

lace https://vercel.com/
      </button>

      <Link
        href={`http://localhost:${port}/nav/about`}
        id="absolute-local-link"
      >
        http://localhost:{port}/nav/about
      </Link>

      <Link
        href={`h

router.push('https://vercel.com/')}
      >
        push https://vercel.com/
      </button>
      <br />
      <button
        id="router-replace"
        onClick={() => router.replace('https://vercel.com/')}
      >
        rep


import Link from 'next/link'
import { withRouter } from 'next/router'

export default withRouter(({ router: { asPath, query } }) => {
  return (

{JSON.stringify(query)}

        <Link
          href="/nav/as-path-pushstate?something=hello"
          as="/something/hello"
          id="hello"
        >
          hello
        </Link>

        <Link href="/nav/as-path-pushstate" as="/

        </Link>
      </div>
      {query.something === 'hello' && (
        <Link
          href="/nav/as-path-pushstate?something=hello"
          as="/something/same-query"
          id="same-query"
        >
          same query
        </Link>

something/else" id="else">
          else
        </Link>
      </div>
      <div>
        <Link
          href="/nav/as-path-pushstate"
          as="/nav/as-path-pushstate"
          id="hello2"
        >
          normal hello


 } from 'react'
import Router from 'next/router'

let count = 0

export default class SelfReload extends Component {
  static getInitialProps({ res }) {
    if (res) return { count: 0 }
    count += 1

    return { count }
  }

  handleAClick = () => {
    Router.push(
      '/nav/hash-changes-with-state',
      '/nav/hash-changes-with-state#hello' + Math.random(),
      {
        historyCount: (window.history.state?.options?.historyCount || 0) + 1,
        shallowHistoryCount: window.history.state?.options

historyCount: window.history.state?.options?.historyCount,
        shallowHistoryCount:
          (window.history.state?.options?.shallowHistoryCount || 0) + 1,
      }
    )
  }

  render() {
    return (

COUN

?.shallowHistoryCount,
      }
    )
  }

  handleAShallowClick = () => {
    Router.push(
      '/nav/hash-changes-with-state#',
      '/nav/hash-changes-with-state#hello' + Math.random(),
      {
        shallow: true,


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

describe('Has CSS Module in computed styles in Development', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'fixtures/dev-module'),
  })

  it('should have CSS for page', async () => {
    const browser = await next.browser('/')

    const currentColor = await browser.eval(
      `window.getComputedStyle(document.querySelector('#verify-red')).color`
    )
    expect(currentColor).toMatchInlineSnapsho

emounting <input>', async () => {
    const browser = await next.browser('/')

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

t(`"rgb(255, 0, 0)"`)
  })
})

describe('Can hot reload CSS Module without losing state', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'fixtures/hmr-module'),
  })

  it('should update CSS color without r


 'path'

describe('Can hot reload CSS without losing state', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'fixtures/multi-page'),
  })

  it('should update CSS color without remounting <input>', async () => {
    const browser = await next.browser('/page1')

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

    const currentColor = await browser.eval(

ile(cssPath)
    await next.patchFile(
      cssPath,
      originalCss.replace('color: red', 'color: purple')
    )

    try {
      await retry(async () => {
        const color = await browser.eval(
          `window.getComputedStyle(document.querySelec

     `window.getComputedStyle(document.querySelector('.red-text')).color`
    )
    expect(currentColor).toMatchInlineSnapshot(`"rgb(255, 0, 0)"`)

    const cssPath = 'styles/global1.css'
    const originalCss = await next.readF


utils'
import { check } from 'next-test-utils'

describe('next-config-ts - dev-hmr', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })
  it('should output config file change', async () => {
    await check(async () => next.cliOutput, /ready/i)

    await check(async () => {
      await next.patchFile('next.config.ts', (content) => {
        return content.replace(
          '// target',
          `async redirects() {
            return [
              {
                source: '/about',

rmanent: false,
              },
            ]
          },`
        )
      })
      return next.cliOutput
    }, /Found a change in next\.config\.ts\. Restarting the server to apply the changes\.\.\./)

    await check(() => next.fetch('/about').then((re

                destination: '/',
                pe


 join } from 'path'
import fs from 'fs-extra'

describe('tsconfig-path-reloading', () => {
  const tsConfigFile = 'tsconfig.json'
  const indexPage = 'pages/index.tsx'

  const tsConfigContent = fs.readFileSync(
    join(__dirname, 'app/tsconfig.json'),
    'utf8'
  )

  function runTests({
    addAfterStart,
    testBaseUrl,
  }: {
    addAfterStart?: boolean
    testBaseUrl: boolean
  }) {
    const typescriptVersion = testBaseUrl ? '5.9.3' : 'latest'

    const { next } = nextTestSetup({
      files: {

 : {
              [tsConfigFile]: tsConfigContent,
            }),
      },
      dependencies: {
        typescript: typescriptVersion,
        '@types/react': 'latest',
        '@types/node': 'latest',
      },
    })

    if (addAfterStart) {
      bef

       components: new FileRef(join(__dirname, 'app/components')),
        pages: new FileRef(join(__dirname, 'app/pages')),
        lib: new FileRef(join(__dirname, 'app/lib')),
        ...(addAfterStart
          ? {}


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

  const navigateTo = async (browser: any, selector: string) =>
    await browser
      .waitForElementByCss('#' + selector + '-link')
      .click()
      .waitForElementByCss('#' + selector)

  const getAnnouncedTitle = async (browser: any) =>
    await browser.waitForElementByCss('#__next-route-announcer__').text()

  const getDocumentTitle = async (browser: any) =>
    await browser.eval('document.title')

  const getMainHeadingTitle = async (browse

= await getAnnouncedTitle(browser)
      expect(title).toBe('')
    })

    it('has aria-live="assertive" and role="alert"', async () => {
      const browser = await next.browser('/')
      const routeAnnouncer = await browser.waitForElementByCss(

r: any) =>
    await browser.elementByCss('h1').text()

  describe('<RouteAnnouncer />', () => {
    it('should not have the initial route announced', async () => {
      const browser = await next.browser('/')
      const title


e development errors', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  let middlewareContent: string
  beforeAll(async () => {
    middlewareContent = await next.readFile('middleware.js')
  })

  async function assertMiddlewareFetch(hasMiddleware: boolean, path = '/') {
    await retry(async () => {
      const res = await next.fetch(path)
      expect(res.status).toBe(200)
      expect(res.headers.get('x-from-middleware')).toBe(
        hasMiddleware ? 'true' : null
      )
    })

').text()
      expect(fromMiddleware).toBe(hasMiddleware ? 'true' : 'null')
    })
  }

  describe('when middleware is removed', () => {
    let stderrLog = ''
    let onStderr: ((msg: string) => void) | undefined

    beforeEach(async () => {
      stder

  }

  async function assertMiddlewareRender(hasMiddleware: boolean, path = '/') {
    const browser = await next.browser(path)
    await retry(async () => {
      const fromMiddleware = await browser.elementById('from-middleware


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

describe('custom-app-hmr', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })
  it('should not do full reload when simply editing _app.js', async () => {
    const customAppFilePath = 'pages/_app.js'
    const browser = await next.browser('/')
    await browser.eval('window.hmrConstantValue = "should-not-change"')

    const customAppContent = await next.readFile(customAppFilePath)
    const newCustomAppContent = customAppContent.r

ect(pText).toBe('hmr text changed')

      // Should keep the value on window, which indicates there's no full reload
      const hmrConstantValue = await browser.eval('window.hmrConstantValue')
      expect(hmrConstantValue).toBe('should-not-change')

eplace(
      'hmr text origin',
      'hmr text changed'
    )
    await next.patchFile(customAppFilePath, newCustomAppContent)

    await check(async () => {
      const pText = await browser.elementByCss('h1').text()
      exp


estSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  describe('inside getInitialProps', () => {
    it('should show the correct asPath with a Link with as prop', async () => {
      const browser = await next.browser('/nav')
      const asPath = await browser
        .elementByCss('#as-path-link')
        .click()
        .waitForElementByCss('.as-path-content')
        .elementByCss('.as-path-content')
        .text()

      expect(asPa

       .elementByCss('#as-path-link-no-as')
        .click()
        .waitForElementByCss('.as-path-content')
        .elementByCss('.as-path-content')
        .text()

      expect(asPath).toBe('/nav/as-path')
      await browser.close()
    })
  })

  de

th).toBe('/as/path')
      await browser.close()
    })

    it('should show the correct asPath with a Link without the as prop', async () => {
      const browser = await next.browser('/nav')
      const asPath = await browser


port { waitForNoRedbox, waitFor } from 'next-test-utils'
import path from 'path'
import { nextTestSetup } from 'e2e-utils'

describe('Client navigation with foreign history manipulation', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  it('should ignore history state without options', async () => {
    const browser = await next.browser('/nav')
    // push history object without options
    await brow

waitFor(1000)
    await waitForNoRedbox(browser)
  })

  it('should ignore history state with an invalid url', async () => {
    const browser = await next.browser('/nav')
    // push history object wit invalid url (not relative)
    await browser.eval(

ser.eval(
      'window.history.pushState({ url: "/whatever" }, "", "/whatever")'
    )
    await browser.elementByCss('#about-link').click()
    await browser.waitForElementByCss('.nav-about')
    await browser.back()
    await


test-utils'
import path from 'path'
import { nextTestSetup } from 'e2e-utils'

describe('Client navigation querystring', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  describe('with the same page but different querystring', () => {
    it('should navigate the page', async () => {
      const browser = await next.browser('/nav/querystring?id=1')
      const text = await browser
        .elementByCss(

 => {
      const browser = await next.browser('/nav/querystring?id=1')
      const text = await browser
        .elementByCss('#main-page')
        .click()
        .waitForElementByCss('.nav-id-0')
        .elementByCss('p')
        .text()

      expect

'#next-id-link')
        .click()
        .waitForElementByCss('.nav-id-2')
        .elementByCss('p')
        .text()

      expect(text).toBe('2')
      await browser.close()
    })

    it('should remove querystring', async ()


stSetup } from 'e2e-utils'

describe('Client navigation scroll', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  describe('resets scroll at the correct time', () => {
    it('should reset scroll before the new page runs its lifecycles (<Link />)', async () => {
      const browser = await next.browser('/nav/long-page-to-snap-scroll')

      // Scrolls to item 400 on the page
      await browser

   // Go to snap scroll page
      await browser
        .elementByCss('#goto-snap-scroll-position')
        .click()
        .waitForElementByCss('#scroll-pos-y')

      const snappedScrollPosition = await browser.eval(
        'document.getElementById("s

  .waitForElementByCss('#long-page-to-snap-scroll')
        .elementByCss('#scroll-to-item-400')
        .click()

      const scrollPosition = await browser.eval('window.pageYOffset')
      expect(scrollPosition).toBe(7208)


 [shouldInsertScript, toggleScript] = React.useReducer((b) => !b, false)

  const scriptAsyncTrue = <script src="/test-async-true.js" async></script>
  const scriptAsyncFalse = (
    <script src="/test-async-false.js" async={false}></script>
  )

  return (
    <div>
      <Head>
        {/* this will not render */}
        <meta charSet="utf-8" />
        {/* this will get rendered */}
        <meta charSet="iso-8859-5" />

        {/* this will not render */}
        <meta name="viewport" content="width=d

/}
        <meta name="empty-content" content={undefined} />

        {/* allow duplicates for specific tags */}
        <meta property="article:tag" content="tag1" key="tag1key" />
        <meta property="article:tag" content="tag2" key="tag2key" />

evice-width" />
        {/* this will override the default */}
        <meta name="viewport" content="width=device-width,initial-scale=1" />

        <meta content="my meta" />

        {/* this will not render the content prop *


next-test-utils'
import fs from 'fs-extra'
import path from 'path'

const READ_ONLY_PERMISSIONS = 0o444
const READ_WRITE_PERMISSIONS = 0o644

let pageHello = 'pages/hello.js'

describe('Read-only source HMR', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, '..'),
    skipStart: true,
    env: {
      __NEXT_TEST_WITH_DEVTOOL: '1',
      // Events can be finicky in CI. This switches to a more reliable
      // polling method.
      CHOKIDAR_USEPOLLING: 'true',
      CHOKIDAR_INTERV

content: string | undefined) => string | undefined,
    runWithTempContent: (context: { newFile: boolean }) => Promise<void>
  ) {
    const filePath = path.join(next.testDir, filename)
    const exists = await fs
      .access(filePath)
      .then(() =>

AL: '500',
    },
  })

  beforeAll(async () => {
    await fs.chmod(path.join(next.testDir, pageHello), READ_ONLY_PERMISSIONS)
    await next.start()
  })

  async function patchFileReadOnly(
    filename: string,
    content: (


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

describe('Has CSS Module in computed styles in Development', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'fixtures', 'dev-module'),
  })

  it('should have CSS for page', async () => {
    const browser = await next.browser('/')

    const currentColor = await browser.eval(
      `window.getComputedStyle(document.querySelector('#verify-red')).color`
    )
    expect(currentC

ay: 500,
  })

  it('should update CSS color without remounting <input>', async () => {
    const browser = await next.browser('/')

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

olor).toMatchInlineSnapshot(`"rgb(255, 0, 0)"`)
  })
})

describe('Can hot reload CSS Module without losing state', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'fixtures', 'hmr-module'),
    patchFileDel


owser.elementByCss('[data-nextjs-error-code]')
    const code = await errorCode.getAttribute('data-nextjs-error-code')
    expect(code).toBe('E40')
  })

  it('sends feedback when clicking helpful button', async () => {
    const feedbackRequests: string[] = []
    const browser = await next.browser('/known-client-error', {
      beforePageLoad(page) {
        page.route(/__nextjs_error_feedback/, (route) => {
          const url = new URL(route.request().url())
          feedbackRequests.push(url.pathname

Mark as helpful' }).click()

    expect(
      await browser
        .getByRole('region', { name: 'Error feedback' })
        .getByRole('status')
        .textContent()
    ).toEqual('Thanks for your feedback!')
    expect(feedbackRequests).toEqual([

+ url.search)

          route.fulfill({ status: 204, body: 'No Content' })
        })
      },
    })

    await browser.elementByCss('button').click() // clicked "break on client"
    await browser.getByRole('button', { name: '


retry } from 'next-test-utils'

describe('Invalid revalidate values', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not show error initially', async () => {
    const html = await next.render('/ssg')
    expect(html).toContain('a-ok')
  })

  it('should not show error for false revalidate value', async () => {
    const originalContent = await next.readFile('pages/ssg.js')
    await next.patchFile(
      'pages/ssg.js',
      originalContent.replace('revalidate: 1', 're

w error for true revalidate value', async () => {
    const originalContent = await next.readFile('pages/ssg.js')
    await next.patchFile(
      'pages/ssg.js',
      originalContent.replace('revalidate: 1', 'revalidate: true')
    )

    await retry(asyn

validate: false')
    )

    await retry(async () => {
      const html = await next.render('/ssg')
      expect(html).toContain('a-ok')
    })

    await next.patchFile('pages/ssg.js', originalContent)
  })

  it('should not sho


or } from 'next-test-utils'
import path from 'path'
import { nextTestSetup } from 'e2e-utils'

describe('Client navigation on error pages', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  it('should not reload when visiting /_error directly', async () => {
    const { status } = await fetchViaHTTP(next.appPort, '/_error')
    const browser = await next.browser('/_error')

    await browser.eval('windo

    const html = await browser.eval('document.documentElement.innerHTML')

    expect(status).toBe(404)
    expect(html).toContain('This page could not be found')
    expect(html).toContain('404')
  })

  describe('with 404 pages', () => {
    it('should

w.hello = true')

    // wait on-demand-entries timeout since it can trigger
    // reloading non-stop
    for (let i = 0; i < 15; i++) {
      expect(await browser.eval('window.hello')).toBe(true)
      await waitFor(1000)
    }


on rendering <Head />', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
  })

  function render(
    pathname: Parameters<typeof renderViaHTTP>[1],
    query?: Parameters<typeof renderViaHTTP>[2]
  ) {
    return renderViaHTTP(next.appPort, pathname, query)
  }

  it('should handle undefined prop in head server-side', async () => {
    const html = await render('/head')
    const $ = cheerio.load(html)
    const value = 'content' in $('meta[name="empty-content"]').attr

="utf-8" data-next-head=""/>')
    expect(html).toContain('next-head, but only once.')
  })

  test('header renders default viewport', async () => {
    const html = await render('/default-head')
    expect(html).toContain(
      '<meta name="viewport" con

()

    expect(value).toBe(false)
  })

  // default-head contains an empty <Head />.
  test('header renders default charset', async () => {
    const html = await render('/default-head')
    expect(html).toContain('<meta charSet


retry } from 'next-test-utils'

describe('typescript-native-preview', () => {
  const { next } = nextTestSetup({
    files: {
      'app/layout.tsx': `
        import { ReactNode } from 'react'
        export default function Root({ children }: { children: ReactNode }) {
          return (

              {children}

          )
        }
      `,
      'app/page.tsx': `
        export default function Page() {
          return
hello world

        }

,
          noEmit: true,
          esModuleInterop: true,
          module: 'esnext',
          moduleResolution: 'bundler',
          resolveJsonModule: true,
          isolatedModules: true,
          jsx: 'preserve',
          incremental: true,

    `,
      'tsconfig.json': JSON.stringify({
        compilerOptions: {
          target: 'ES2017',
          lib: ['dom', 'dom.iterable', 'esnext'],
          allowJs: true,
          skipLibCheck: true,
          strict: true


git repository is dirty[^\n]*\n?/g, '')
      .replace(/.*at async handler .*next-route-loader.*/g, '')
      .replace(/.*at async handleResponse.*/g, '')
      .replace(/.*at async doRender \(.*/g, '')
      .split(/\n/)
      .filter((item) => {
        const trimmed = item.trim()
        if (!trimmed) return false
        // Drop bootstrap/startup banner lines that may appear after
        // `next.cliOutput` was sliced. The Experiments banner is logged
        // asynchronously after the dev server repo

rn false
        // Drop compiling indicator lines (e.g. "○ Compiling /gsp ...").
        if (trimmed.startsWith('○ ')) return false
        return true
      })
      .join('\n')
  }

  it('should show server-side error for gsp page correctly', async () =

rts ready (see
        // `logExperimentalInfo` in `start-server.ts`), so it can race
        // with the test capturing `cliOutputIdx`.
        if (trimmed.startsWith('- ')) return false
        if (/^[✓⚠△] /.test(trimmed)) retu


t } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
  })

  it.each([true, false])(
    'should handle boolean async prop in next/head client-side: %s',
    async (bool) => {
      const browser = await next.browser('/head')
      const value = await browser.eval(
        `document.querySelector('script[src="/test-async-${JSON.stringify(
          bool
        )}.js"]').async`
      )

      expect(value).toBe(bool)
    }
  )

  it('should only execute async and defer scripts once', async () =

wser.eval('window.__test_defer_executions'))).toBe(1)

    await browser.elementByCss('#reverseScriptOrder').click()
    await waitFor(2000)

    expect(Number(await browser.eval('window.__test_async_executions'))).toBe(1)
    expect(Number(await browser.e

> {
    const browser = await next.browser('/head')

    await browser.waitForElementByCss('h1')
    await waitFor(2000)
    expect(Number(await browser.eval('window.__test_async_executions'))).toBe(1)
    expect(Number(await bro


retry } from 'next-test-utils'

describe('_app/_document add HMR', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  // TODO: figure out why test fails.
  it.skip('should HMR when _app is added', async () => {
    const browser = await next.browser('/')
    try {
      const html = await browser.eval('document.documentElement.innerHTML')
      expect(html).not.toContain('custom _app')
      expect(html).toContain('index page')

      await next.patchFile(
        'pages/_app.js',

     )

      await retry(async () => {
        const html = await browser.eval('document.documentElement.innerHTML')
        expect(html).toContain('custom _app')
        expect(html).toContain('index page')
      })
    } finally {
      await next.delet

`
        export default function MyApp({ Component, pageProps }) {
          return (
            <>

custom _app

              <Component {...pageProps} />
            </>
          )
        }
      `


tTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  describe('when hash changes', () => {
    describe('check hydration mis-match', () => {
      it('should not have hydration mis-match for hash link', async () => {
        const browser = await next.browser('/nav/hash-changes')
        const browserLogs = await browser.log()
        let found = false
        browserLogs.forEach((log) => {
          console.log('log.message', log.mess

not run getInitialProps', async () => {
        const browser = await next.browser('/nav/hash-changes')

        await browser.elementByCss('#via-link').click()

        await retry(async () => {
          expect(await browser.elementByCss('p').text()).toB

age)
          if (log.message.includes('Warning: Prop')) {
            found = true
          }
        })
        expect(found).toEqual(false)
      })
    })

    describe('when hash change via Link', () => {
      it('should


t-test-utils'
import path from 'path'
import { nextTestSetup } from 'e2e-utils'

describe('Client Navigation', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
    env: {
      TEST_STRICT_NEXT_HEAD: String(true),
    },
  })

  describe('with <a/> tag inside the <Link />', () => {
    it('should navigate the page', async () => {
      const browser = await next.browser('/nav/about')
      const text = await browser
        .elementByCss('#home-link')
        .click()

c () => {
      const browser = await next.browser('/nav')

      await browser
        .elementByCss('#increase')
        .click()
        .elementByCss('#target-link')
        .click()

      await waitFor(1000)

      const counterText = await browser.e

       .waitForElementByCss('.nav-home')
        .elementByCss('p')
        .text()

      expect(text).toBe('This is the home.')
      await browser.close()
    })

    it('should not navigate if the <a/> tag has a target', asyn


tureBuffer,
  readFixtureText,
} from './utils'

describe('metadata-files-static-output-dynamic-route', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
  })

  if (skipped) {
    return
  }

  it('should have correct link tags for dynamic page with static placeholder', async () => {
    const browser = await next.browser('/dynamic/123')

    // Static metadata files under dynamic routes use "-" as placeholder
    // since the file content is the same regardless of params
    expect

 },
         {
           "href": "/dynamic/-/icon.png",
           "rel": "icon",
           "type": "image/png",
         },
         {
           "href": "/favicon.ico",
           "rel": "icon",
           "type": "image/x-icon",
         },
         {

(await getCommonMetadataHeadTags(browser)).toMatchInlineSnapshot(`
     {
       "links": [
         {
           "href": "/dynamic/-/apple-icon.png",
           "rel": "apple-touch-icon",
           "type": "image/png",


 readFixtureText,
} from './utils'

describe('metadata-files-static-output-group-route', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
  })

  if (skipped) {
    return
  }

  it('should have correct link tags for group page', async () => {
    const browser = await next.browser('/group')

    expect(await getCommonMetadataHeadTags(browser)).toMatchInlineSnapshot(`
     {
       "links": [
         {
           "href": "/favicon.ico",
           "rel": "icon",
           "type":

          "rel": "icon",
           "type": "image/png",
         },
         {
           "href": "/manifest.json",
           "rel": "manifest",
         },
       ],
       "metas": [
         {
           "name": "twitter:card",
         },
         {

"image/x-icon",
         },
         {
           "href": "/group/apple-icon-131tc6.png",
           "rel": "apple-touch-icon",
           "type": "image/png",
         },
         {
           "href": "/group/icon-131tc6.png",


retry } from 'next-test-utils'

describe('app-dir action progressive enhancement', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      nanoid: '4.0.1',
      'server-only': 'latest',
    },
  })

  it('should support formData and redirect without JS', async () => {
    let responseCode: number | undefined
    const browser = await next.browser('/server', {
      disableJavaScript: true,
      beforePageLoad(page) {
        page.on('response', (response) => {

yId('name').type('test')
    await browser.elementById('submit').click()

    await retry(async () => {
      expect(await browser.url()).toBe(
        `${next.url}/header?name=test&hidden-info=hi`
      )
    })

    expect(responseCode).toBe(303)
  })

const url = new URL(response.url())
          const status = response.status()
          if (url.pathname.includes('/server')) {
            responseCode = status
          }
        })
      },
    })

    await browser.elementB


import { accountForOverhead } from './account-for-overhead'
import { join } from 'path'

const CONFIG_ERROR =
  'Server Actions Size Limit must be a valid number or filesize format larger than 1MB'

describe('app-dir action size limit invalid config', () => {
  const { next, isNextStart, isNextDeploy, skipped } = nextTestSetup({
    files: __dirname,
    overrideFiles: process.env.TEST_NODE_MIDDLEWARE
      ? {
          'middleware.js': new FileRef(join(__dirname, 'middleware-node.js')),
        }
      :

gs.push(stripAnsi(log.trim()))
    }

    next.on('stdout', onLog)
    next.on('stderr', onLog)
  })

  afterEach(async () => {
    logs.length = 0

    await next.stop()
  })

  if (isNextStart) {
    it('should error if serverActions.bodySizeLimit config

 {},
    skipStart: true,
    dependencies: {
      nanoid: '4.0.1',
      'server-only': 'latest',
    },
  })
  if (skipped) return

  const logs: string[] = []

  beforeAll(() => {
    const onLog = (log: string) => {
      lo


').error(`Invalid action entry ${item}`, err)
          throw err
        }
      }
      for (const item in referenceManifest.edge) {
        try {
          const itemInfo = referenceManifest.edge[item]

          foundExportNames.push(itemInfo.exportedName)

          expect(itemInfo.filename).toBeString()
          expect(itemInfo.exportedName).toBeString()
        } catch (err) {
          require('console').error(`Invalid action entry ${item}`, err)
          throw err
        }
      }

      expect(

('should handle action correctly with middleware rewrite', async () => {
    const browser = await next.browser('/rewrite-to-static-first')
    let actionRequestStatus: number | undefined

    browser.on('response', async (res) => {
      if (
        res.

foundExportNames).toContain('setCookie')
      expect(foundExportNames).toContain('getCookie')
      expect(foundExportNames).toContain('getHeader')
      expect(foundExportNames).toContain('setCookieWithMaxAge')
    })
  }

  it


s page is forced into dynamic rendering because POST requests to
// a static/ISR page will cause an error when deployed.
export const dynamic = 'force-dynamic'

export default function Home() {
  return (

POST /api-redirect (`redirect()`)

      <form action="/redirects/api-redirect" method="POST">
        <input type="submit" value="Submit" id="submit-api-redirect" />
      </form>

POST /api-redirect-permanent (`permanentRedirect()`)

      <form ac

7

      <form action="/redirects/api-redirect-307" method="POST">
        <input type="submit" value="Submit" id="submit-api-redirect-307" />
      </form>

POST /api-reponse-redirect-308

      <form action="/redirects/api-redirect-308"

tion="/redirects/api-redirect-permanent" method="POST">
        <input
          type="submit"
          value="Submit"
          id="submit-api-redirect-permanent"
        />
      </form>
      <h1>POST /api-reponse-redirect-30


mport { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

export default async function Page({ searchParams }) {
  const foo = (await cookies()).get('foo')
  const bar = (await cookies()).get('bar')
  return (

        foo={foo ? foo.value : ''}; bar={bar ? bar.value : ''}

      <form
        action={async () => {
          'use server'
          ;(await cookies()).delete('foo')
          ;(await cookies()).set('bar', '2')
          redirect('/redirect

? ''}</h2>
      <form
        action={async () => {
          'use server'
          redirect('/redirects/action-redirect/redirect-target?baz=1')
        }}
      >
        <button type="submit" id="redirect-with-search-params">
          Redirect with Se

s/action-redirect/redirect-target')
        }}
      >
        <button type="submit" id="redirect-with-cookie-mutation">
          Set Cookies and Redirect
        </button>
      </form>
      <h2>baz={(await searchParams).baz ?


rt Link from 'next/link'

import { cookies } from 'next/headers'
import RedirectClientComponent from './client'

export default async function Page() {
  const cookie = (await cookies()).get('random')
  const data = await fetch(
    'https://next-data-api-endpoint.vercel.app/api/random?page',
    {
      next: { revalidate: 3600, tags: ['thankyounext'] },
    }
  ).then((res) => res.text())

  const data2 = await fetch(
    'https://next-data-api-endpoint.vercel.app/api/random?a=b',
    {
      next: { reva

ext">
          {data}
        {' '}

          <Link href="/revalidate-2" id="another">
            /revalidate-2
          </Link>

        revalidate (tags: thankyounext, justputit):{' '}

lidate: 3600, tags: ['thankyounext', 'justputit'] },
    }
  ).then((res) => res.text())

  return (
    <>

revalidate

        {' '}
        revalidate (tags: thankyounext): <span id="thankyoun


lient'
import { useTransition, useState } from 'react'
import { badAction, getServerData } from './actions'

export default function Component() {
  const [isPending, startTransition] = useTransition()
  const [wasSubmitted, setWasSubmitted] = useState(false)
  return (
    <>
      {wasSubmitted &&
Submitted!
}
      <button
        id="good-action"
        disabled={isPending}
        onClick={() => {
          startTransition(() => {
            getServerData()

      </button>

      <button
        id="bad-action"
        disabled={isPending}
        onClick={() => {
          startTransition(() => {
            badAction()
              .catch(() => {
                console.log('error caught in user code')

.catch(() => {
                console.log('error caught in user code')
              })
              .finally(() => {
                setWasSubmitted(true)
              })
          })
        }}
      >
        Submit Action


n Counter({ inc, dec, double, slowInc }) {
  const [count, setCount] = useState(0)

  return (

{count}

      <button
        id="inc"
        onClick={async () => {
          const newCount = await inc(count)
          setCount(newCount)
        }}
      >
        +1
      </button>
      <button
        id="slow-inc"
        onClick={async () => {
          const newCount = await slowInc(count)
          setCount(newCount)
        }}
      >
        +1 (Slow)
      </but

{async () => {
          const newCount = await dec(count)
          setCount(newCount)
        }}
      >
        -1
      </button>
      <button
        id="double"
        onClick={async () => {
          const newCount = await double(count)

ton>
      <button
        id="dec"
        onClick=


nd } from 'next/navigation'

async function action(formData) {
  'use server'
  redirect(
    '/header?name=' +
      formData.get('name') +
      '&hidden-info=' +
      formData.get('hidden-info')
  )
}

async function nowhere() {
  'use server'
  notFound()
}

async function here() {
  'use server'
  // nothing
}

async function file(formData) {
  'use server'
  const file = formData.get('file')
  console.log('File name:', file.name, 'size:', file.size)
}

export default function Form() {
  const b = 1

'
    redirect('/header?result=' + (a + b + c))
  }

  return (
    <>
      <hr />
      <form action={action}>
        <input type="text" name="hidden-info" defaultValue="hi" hidden />
        <input type="text" name="name" id="name" required />

 async function add(a, formData) {
    'use server'
    // Bind variable, closure variable, and argument.
    redirect('/header?result=' + (a + b + Number(formData.get('n'))))
  }

  async function add3(a, b, c) {
    'use server


mport Counter from './counter'
import Form from './form'
import ClientForm from './client-form'

import dec, { slowInc } from './actions'
import { log } from './actions-2'
import { inc } from './actions-3'

export default function Page() {
  const two = { value: 2 }

  // https://github.com/vercel/next.js/issues/58463
  const data = '你好'

  return (
    <>
      <Counter
        inc={inc}
        dec={dec}
        slowInc={slowInc}
        double={async (x) => {
          'use server'
          if (data ===

       return x * two.value
          }
          // Wrong answer
          return 42
        }}
      />
      <Form />
      <ClientForm />
      <form>
        <button id="log" formAction={log}>
          log
        </button>
      </form>
    </>
  )


ort default function UI({
  getCookie,
  getHeader,
  setCookie,
  setCookieAndRedirect,
  getAuthedUppercase,
}) {
  const [result, setResult] = useState('')

  return (

{result}

      <button
        id="cookie"
        onClick={async () => {
          // set cookie
          const random = Math.random()
          document.cookie = `random=${random}`
          const res = await getCookie('random')
          setResult(random + ':' + res.value)
        }}
      >
        getCookie

     setResult(
            random +
              ':' +
              res.value +
              ':' +
              document.cookie.match(/random-server=([^;]+)/)?.[1]
          )
        }}
      >
        setCookie
      </button>
      <button

     </button>
      <button
        id="setCookie"
        onClick={async () => {
          // set cookie on server side
          const random = Math.random()
          const res = await setCookie('random-server', random)


e, getHeader, setCookie } from '../../actions'

const getReferrer = getHeader.bind(null, 'referer')
const setTestCookie = setCookie.bind(null, 'test', '42')
const getTestCookie = getCookie.bind(null, 'test')

export default function Page() {
  const [referer, getReferrerAction] = useActionState(getReferrer, null)

  const [cookie, getTestCookieAction] = useActionState<ReturnType<
    typeof getCookie
  > | null>(getTestCookie, null)

  return (
    <>
      <form action={getReferrerAction}>
        <p id="r

="get-referer">Get Referer</button>
      </form>
      <form action={getTestCookieAction}>

{cookie?.value}

        <button id="set-cookie" formAction={setTestCookie}>
          Set Cookie
        </button>
        <button id="ge

eferer">{referer ?? '<null>'}</p>
        <button id


Page() {
  const data1 = await fetch(
    'https://next-data-api-endpoint.vercel.app/api/random?a',
    {
      next: { tags: ['thankyounext'] },
    }
  ).then((res) => res.text())

  const data2 = await fetch(
    'https://next-data-api-endpoint.vercel.app/api/random?b',
    {
      next: { tags: ['justputit'] },
    }
  ).then((res) => res.text())

  return (
    <>

another route

        revalidate (tags: thankyounext): {data1}

an id="justputit">{data2}</span>
      </p>
      <form>
        <button
          id="revalidate"
          formAction={async () => {
            'use server'
            updateTag('thankyounext')
            updateTag('justputit')
          }}
        >

      <p>
        revalidate (tags: justputit): <sp


client'

import { useTransition } from 'react'
import { action } from './actions'

export default function Page() {
  const [, startTransition] = useTransition()

  return (
    <main>
      <p>
        This button will call a server action and pass something unserializable
        like a class instance. We expect this action to error with a reasonable
        message explaning what happened
      </p>
      <button
        id="submit"
        onClick={async () => {
          await action(new Foo())

      Submit
      </button>

      <button
        id="submit-transition"
        onClick={async () => {
          startTransition(() => action())
        }}
      >
        Action that triggers an error
      </button>
    </main>
  )
}

class Foo {
  va


mport { accountForOverhead } from '../../account-for-overhead'

async function action(formData) {
  'use server'
  const payload = formData.get('payload').toString()
  console.log('size =', payload.length)
}

export default function Page() {
  return (
    <>
      <form action={action}>
        <input
          type="hidden"
          name="payload"
          value={'a'.repeat(accountForOverhead(1))}
        />
        <button type="submit" id="size-1mb">
          SUBMIT 1mb
        </button>
      </form

   </button>
      </form>
      <form action={action}>
        <input
          type="hidden"
          name="payload"
          value={'a'.repeat(accountForOverhead(3))}
        />
        <button type="submit" id="size-3mb">
          SUBMIT 3mb

>
      <form action={action}>
        <input
          type="hidden"
          name="payload"
          value={'a'.repeat(accountForOverhead(2))}
        />
        <button type="submit" id="size-2mb">
          SUBMIT 2mb


eState } from 'react'

import double, {
  inc,
  dec,
  redirectAction,
  getHeaders,
  renamed,
  slowInc,
} from './actions'
import { test } from './actions-lib'

export default function Counter() {
  const [count, setCount] = useState(0)
  return (

{count}

      <button
        id="inc"
        onClick={async () => {
          const newCount = await inc(count)
          setCount(newCount)

          // test renamed action
          renamed()
        }}
      >

        id="dec"
        onClick={async () => {
          const newCount = await dec(count)
          setCount(newCount)
        }}
      >
        -1
      </button>
      <button
        id="double"
        onClick={async () => {
          const newCoun

+1
      </button>
      <button
        id="slow-inc"
        onClick={async () => {
          const newCount = await slowInc(count)
          setCount(newCount)
        }}
      >
        +1 (Slow)
      </button>
      <button


ort { redirectAction } from '../actions'

export default function Page() {
  return (
    <div>
      <form>
        <button
          id="redirect-relative"
          formAction={() => redirectAction('/redirect-target')}
        >
          redirect relative
        </button>
      </form>
      <form>
        <button
          id="redirect-external"
          formAction={() =>
            redirectAction(
              'https://next-data-api-endpoint.vercel.app/api/random?page'
            )
          }

>
      </form>
      <form>
        <button
          id="redirect-absolute"
          formAction={() =>
            redirectAction(location.origin + '/redirect-target')
          }
        >
          redirect internal with domain
        </button>

      >
          redirect external
        </button


eState } from 'react'

import double, { inc, dec, redirectAction, getHeaders } from '../actions'

export default function Counter() {
  const [count, setCount] = useState(0)
  return (

{count}

      <button
        id="inc"
        onClick={async () => {
          const newCount = await inc(count)
          setCount(newCount)
        }}
      >
        +1
      </button>
      <button
        id="dec"
        onClick={async () => {
          const newCount = await dec(count)

       *2
      </button>
      <form>
        <button
          id="redirect-relative"
          formAction={() => redirectAction('/redirect-target')}
        >
          redirect to a relative URL
        </button>
      </form>
      <form>
        <but

   setCount(newCount)
        }}
      >
        -1
      </button>
      <button
        id="double"
        onClick={async () => {
          const newCount = await double(count)
          setCount(newCount)
        }}
      >


mport { updateTag } from 'next/cache'
import { cookies } from 'next/headers'
import Link from 'next/link'

export default async function Page() {
  const randomCookie = (await cookies()).get('random')
  const data = await fetch(
    'https://next-data-api-endpoint.vercel.app/api/random?page',
    {
      next: { revalidate: 3600, tags: ['thankyounext'] },
    }
  ).then((res) => res.text())

  return (
    <>

another route

      <Link href="/revalidate" id="back">
        Back

'use server'
            updateTag('thankyounext')
          }}
        >
          revalidate thankyounext
        </button>
      </form>

        random cookie:{' '}

          {JSON.stringify({ cookie: random

</Link>

        {' '}
        revalidate (tags: thankyounext): {data}

      <form>
        <button
          id="revalidate-tag"
          formAction={async () => {


 metadata-streaming', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should only insert metadata once for parallel routes when slots match', async () => {
    const browser = await next.browser('/parallel-routes')

    expect((await browser.elementsByCss('title')).length).toBe(1)
    expect(await browser.elementByCss('title').text()).toBe('parallel title')

    const $ = await next.render$('/parallel-routes')
    expect($('title').length).toBe(1)
    // We can't ensure if it's

   await browser.elementByCss('[href="/parallel-routes/test-page"]').click()

    await retry(async () => {
      expect(await browser.elementByCss('title').text()).toContain(
        'Dynamic api'
      )
    })

    expect((await browser.elementsByCss('t

inserted into head or body since it's a race condition,
    // where sometimes the metadata can be suspended.
    expect($('title').text()).toBe('parallel title')

    // validate behavior remains the same on client navigations


rom 'next/server'
import Link from 'next/link'

// skip rendering children
export default function Layout({ bar, foo }) {
  return (

Parallel Routes Layout - No Children

      <Link href="/parallel-routes-no-children/first" id="to-no-children-first">
        {`to /parallel-routes-no-children/first`}
      </Link>

      <Link
        href="/parallel-routes-no-children/second"
        id="to-no-children-second"
      >
        {`to /parallel-routes-no-children/second`}

{foo}

{bar}

  )
}

export async function generateMetadata() {
  await connection()
  await new Promise((resolve) => setTimeout(resolve, 300))
  return {
    title: 'parallel-routes-default layout title',
  }


utils'

describe('parallel-routes-and-interception-basepath', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should show parallel intercepted slot with basepath', async () => {
    const browser = await next.browser('/base')
    await browser.elementByCss('#link-to-nested').click()
    const homePage = await browser.elementByCss('#home-page').text()
    const slot = await browser.elementByCss('#nested-page-slot').text()
    expect(homePage).toBe('Home page')
    expect(slot).to

 route via direct link with basepath when parallel intercepted slot exist', async () => {
    const browser = await next.browser('/base/nested')
    const nestedPageFull = await browser
      .elementByCss('#nested-page-full')
      .text()
    expect(nest

Be('Nested Page Slot')
  })
  it('should show normal


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

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

  it('should match the catch-all route when navigating from a page with a similar path depth as the previously matched slot', async () => {
    const browser = await next.browser('/')

    await browser.elementByCss('[href="/comments/some-text"]').click()

    await browser.waitForElementByCss('h1')

    // w

await retry(async () => {
      expect(await browser.elementByCss('h1').text()).toBe('Profile')
    })

    await browser.back()

    await browser.elementByCss('[href="/trending"]').click()

    await retry(async () => {
      expect(await browser.element

e're matching @modal/(...comments)/[productId]
    expect(await browser.elementByCss('h1').text()).toBe('Modal')

    await browser.elementByCss('[href="/u/foobar/l"]').click()

    // we're now matching @modal/[...catchAll]


t.readFile('.next/server/app/api/hello.json.meta')
        ).toBeTruthy()
      }
      expect(
        JSON.parse(await next.render(basePath + '/api/hello.json'))
      ).toEqual({
        pathname: '/api/hello.json',
      })
    })

    it('does not statically generate with dynamic usage', async () => {
      if (isNextStart) {
        expect(
          await next
            .readFile('.next/server/app/api/dynamic.body')
            .catch(() => '')
        ).toBeFalsy()
        expect(
          await

ynamic',
        query: {},
      })
    })
  })

  describe('works with generateStaticParams correctly', () => {
    it.each([
      '/static/first/data.json',
      '/static/second/data.json',
      '/static/three/data.json',
    ])('responds correctly o

next
            .readFile('.next/server/app/api/dynamic.meta')
            .catch(() => '')
        ).toBeFalsy()
      }
      expect(JSON.parse(await next.render(basePath + '/api/dynamic'))).toEqual({
        pathname: '/api/d


ver/web/spec-extension/adapters/headers'
import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies'
import type { Headers as NodeFetchHeaders } from 'node-fetch'

const KEY = 'x-request-meta'

/**
 * Adds a new header to the headers object and serializes it. To be used in
 * conjunction with the `getRequestMeta` function in tests to verify request
 * data from the handler.
 *
 * @param meta metadata to inject into the headers
 * @param headers the existing hea

return {
    ...headers,
    [KEY]: JSON.stringify(meta),
  }
}

/**
 * Adds a cookie to the headers with the provided request metadata. Existing
 * cookies will be merged, but it will not merge request metadata that already
 * exists on an existing cookie

ders on the response to merge with
 * @returns the merged headers with the request meta added
 */
export function withRequestMeta(
  meta: Record<string, any>,
  headers: Record<string, string> = {}
): Record<string, string> {


 type NextRequest } from 'next/server'
import { withRequestMeta } from '../helpers'

const helloHandler = async (
  request: NextRequest,
  { params }: { params?: Promise<Record<string, string | string[]>> }
): Promise<Response> => {
  const { pathname } = request.nextUrl

  if (typeof WebSocket === 'undefined') {
    throw new Error('missing WebSocket constructor!!')
  }

  const resolvedParams = params ? await params : null

  return new Response('hello, world', {
    headers: withRequestMeta({
      meth

    pathname,
    }),
  })
}

export const GET = helloHandler
export const HEAD = helloHandler
export const OPTIONS = helloHandler
export const POST = helloHandler
export const PUT = helloHandler
export const DELETE = helloHandler
export const PATCH = hell

od: request.method,
      params: resolvedParams,


from 'e2e-utils'

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

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

    // we have a top-level catch-all but the /nested dir doesn't have a default/page until the /[foo]/[bar] segment
    // so we expect the top-level catch-all to render
    expect(await browser.elementById('children').text()).toBe(
      '/[locale]/[[...catch

.elementById('nested-children').text()).toBe(
      '/[locale]/nested/[foo]/[bar]/default.tsx'
    )

    // we expect the slot to match since there's a page defined at this segment
    expect(await browser.elementById('slot').text()).toBe(
      '/[locale

All]]/page.tsx'
    )

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

    // we're now at the /[foo]/[bar] segment, so we expect the matched page to be the default (since there's no page defined)
    expect(await browser


 =>
    await browser.eval('document.documentElement.scrollTop')

  const getLeftScroll = async (browser: Playwright) =>
    await browser.eval('document.documentElement.scrollLeft')

  const waitForScrollToComplete = async (
    browser: Playwright,
    options: { x: number; y: number }
  ) => {
    await retry(async function expectScrolledTo() {
      const top = await getTopScroll(browser)
      const left = await getLeftScroll(browser)
      expect({ top, left }).toEqual({ top: options.y, left: options.

  await waitForScrollToComplete(browser, options)
  }

  describe('vertical scroll', () => {
    it('should scroll to top of document when navigating between to pages without layout', async () => {
      const browser = await next.browser('/0/0/100/10000/p

x })
    })
    await assertNoConsoleErrors(browser)
  }

  const scrollTo = async (
    browser: Playwright,
    options: { x: number; y: number }
  ) => {
    await browser.eval(`window.scrollTo(${options.x}, ${options.y})`)


import { useRouter } from 'next/navigation'

export default function Layout({ children }: { children: React.ReactNode }) {
  const router = useRouter()

  // We export these so that we can access them from tests
  useEffect(() => {
    // @ts-ignore
    window.router = router
    // @ts-ignore
    window.React = React
  }, [router])

  return (
    <Suspense
      fallback={
        <html>
          <body />
        </html>
      }
    >
      <html>
        <head></head>
        <body
          style={{

  <div
            style={{
              position: 'fixed',
              top: 0,
              left: 0,
            }}
          >
            <Link id="to-vertical-page" href="1" />
          </div>
          {children}
        </body>
      </html>

          margin: 0,
          }}
        >


n (
    <>
      {
        // Repeat 500 elements
        Array.from({ length: 500 }, (_, i) => (

{i}

        ))
      }

        <Link href="/loading-scroll" id="to-loading-scroll">
          To loading scroll
        </Link>

        <Link href="/invisible-first-element" id="to-invisible-first-element">
          To invisible first element
        </Link>

        <Link href="/fixed-first-element" id="to-fixed-first-e

Link>

        <Link href="/sticky-first-element" id="to-sticky-first-element">
          To sticky first element
        </Link>

        <Link href="/new-metadata">To new metadata</Link>

lement">
          To fixed first element
        </


 readFixtureText,
} from './utils'

describe('metadata-files-static-output-parallel-route', () => {
  if (process.env.__NEXT_CACHE_COMPONENTS) {
    // Cache Components build fails when metadata files are inside a dynamic route.
    //
    // Route "/dynamic/[id]": Next.js encountered uncached or runtime data in `generateMetadata()`.
    //
    // This prevents the page from being prerendered, leading to a slower user experience.
    //
    // Ways to fix this:
    //   - Use a static metadata export instea

onst instant = false` to allow a blocking route
    //
    // Learn more: https://nextjs.org/docs/messages/next-prerender-dynamic-metadata
    // Error occurred prerendering page "/dynamic/[id]". Read more: https://nextjs.org/docs/messages/prerender-error

d of `generateMetadata()`
    //   - Cache the metadata with `"use cache"` in `generateMetadata()`
    //   - Add a dynamic data access (e.g. `await connection()`) to the page to render it at request time
    //   - Set `export c


 readFixtureText,
} from './utils'

describe('metadata-files-static-output-static-route', () => {
  if (process.env.__NEXT_CACHE_COMPONENTS) {
    // Cache Components build fails when metadata files are inside a dynamic route.
    //
    // Route "/dynamic/[id]": Next.js encountered uncached or runtime data in `generateMetadata()`.
    //
    // This prevents the page from being prerendered, leading to a slower user experience.
    //
    // Ways to fix this:
    //   - Use a static metadata export instead

st instant = false` to allow a blocking route
    //
    // Learn more: https://nextjs.org/docs/messages/next-prerender-dynamic-metadata
    // Error occurred prerendering page "/dynamic/[id]". Read more: https://nextjs.org/docs/messages/prerender-error

of `generateMetadata()`
    //   - Cache the metadata with `"use cache"` in `generateMetadata()`
    //   - Add a dynamic data access (e.g. `await connection()`) to the page to render it at request time
    //   - Set `export con


ype error.
import { promises as fs } from 'fs'
import path from 'path'
import type { Playwright } from 'e2e-utils'

// Fixture files live in this directory (`test/e2e/app-dir/metadata-static-file`),
// so we read them from the repo on the test runner. Using `next.readFile` would
// hit the deployed filesystem, which is not available in deploy test mode.
export function readFixtureBuffer(relativePath: string) {
  return fs.readFile(path.join(__dirname, relativePath))
}

export function readFixtureText(relati

urn elements
      .filter((el) => {
        if (el.href.includes('/_next/static')) {
          return false
        }

        return [
          '/favicon.ico',
          '/manifest.json',
          '/manifest.webmanifest',
          // Below may have su

vePath: string) {
  return fs.readFile(path.join(__dirname, relativePath), 'utf8')
}

async function getMetadataLinks(browser: Playwright) {
  const links = await browser.locator('link').evaluateAll((elements: any[]) => {
    ret


retry } from 'next-test-utils'
import { type Collector, connectCollector } from './collector'

const COLLECTOR_PORT = 9876

describe('otel-parent-span-propagation', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    dependencies: require('./package.json').dependencies,
    env: {
      TEST_OTEL_COLLECTOR_PORT: String(COLLECTOR_PORT),
      NEXT_TELEMETRY_DISABLED: '1',
    },
  })

  if (skipped) {
    return
  }

  let collector: Collector

  beforeEach

on, when external OTEL instrumentation (e.g. Datadog,
  // @opentelemetry/instrumentation-http) creates a parent HTTP server span,
  // our fix also propagates http.route to that parent span so APM tools
  // derive the resource name correctly (e.g. "GET /

(async () => {
    collector = await connectCollector({ port: COLLECTOR_PORT })
  })

  afterEach(async () => {
    await collector.shutdown()
  })

  // Verifies that http.route is set on the handleRequest span.
  // In producti


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

describe('app dir - middleware with middleware in src dir', () => {
  const { next } = nextTestSetup({
    files: {
      'src/app': new FileRef(path.join(__dirname, 'app')),
      'next.config.js': new FileRef(path.join(__dirname, 'next.config.js')),
      'src/middleware.js': `
      import { NextResponse } from 'next/server'
      import { cookies } from 'next/headers'

      export async function middleware(

r = await next.browser('/')
    await browser.addCookie({
      name: 'test-cookie',
      value: 'test-cookie-response',
    })
    await browser.refresh()

    const html = await browser.eval('document.documentElement.innerHTML')

    expect(html).toCont

request) {
        const cookie = (await cookies()).get('test-cookie')
        return NextResponse.json({ cookie })
      }
    `,
    },
  })

  it('works without crashing when using RequestStore', async () => {
    const browse


ync () => {
      expect(next.cliOutput).toContain(
        'The "middleware" file convention is deprecated. Please use "proxy" instead.'
      )
    })
  })

  it('should filter correctly after middleware rewrite', async () => {
    const browser = await next.browser('/start')

    await browser.eval('window.beforeNav = 1')
    await browser.eval('window.next.router.push("/rewrite-to-app")')

    await check(async () => {
      return browser.eval('document.documentElement.innerHTML')
    }, /app-dir/)
  }

dge',
      toJson: (res: Response) => res.json(),
    },
    {
      title: 'next/headers',
      path: '/headers',
      toJson: async (res: Response) => {
        const $ = cheerio.load(await res.text())
        return JSON.parse($('#headers').text())

)

  describe.each([
    {
      title: 'Serverless Functions',
      path: '/api/dump-headers-serverless',
      toJson: (res: Response) => res.json(),
    },
    {
      title: 'Edge Functions',
      path: '/api/dump-headers-e


import { check } from 'next-test-utils'
import { join } from 'path'

describe('app-dir action useActionState', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    overrideFiles: process.env.TEST_NODE_MIDDLEWARE
      ? {
          'middleware.js': new FileRef(join(__dirname, 'middleware-node.js')),
        }
      : {},
    dependencies: {
      nanoid: '4.0.1',
    },
  })
  it('should support submitting form state with JS', async () => {
    const browser = await next.browser('/client/for

 }, 'initial-state:test')
  })

  it('should support submitting form state without JS', async () => {
    const browser = await next.browser('/client/form-state', {
      disableJavaScript: true,
    })

    await browser.eval(`document.getElementById('nam

m-state')

    await browser.eval(`document.getElementById('name-input').value = 'test'`)
    await browser.elementByCss('#submit-form').click()

    await check(() => {
      return browser.elementByCss('#form-state').text()


'

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

  async function get$(path: string) {
    const html = await next.render(path)
    return cheerio.load(html)
  }

  it('should disable X-Powered-By header support', async () => {
    const res = await next.fetch('/')
    const header = res.headers.get('X-Powered-By')
    expect(header).not.toBe('Next.js')
  })

  test('correctly imports a package that defines `module` but no `main` in package.json', async () => {

xpect($('#messageInAPackage').text()).toBe('OK')
  })

  it('should have env variables available on the client', async () => {
    const browser = await next.browser('/next-config')
    const envValue = await browser.elementByCss('#env').text()
    expect(

  const $ = await get$('/module-only-content')
    e


document components error', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  async function checkMissing(missing: string[], docContent: string) {
    const outputIndex = next.cliOutput.length
    await next.patchFile('pages/_document.js', docContent)

    await next.render('/').catch(() => {})

    await retry(async () => {
      const newOutput = next.cliOutput.slice(outputIndex)
      expect(newOutput).toContain('missing-document-component')
      expect(newOutput).toContain(missin

ript } from 'next/document'

      class MyDocument extends Document {
        render() {
          return (
            <html>
              <Head />
              <body>
                <Main />
                <NextScript />
              </body>

g.join(', '))
    })

    await next.deleteFile('pages/_document.js')
  }

  it('should detect missing Html component', async () => {
    await checkMissing(
      ['<Html />'],
      `
      import Document, { Head, Main, NextSc


retry } from 'next-test-utils'
import path from 'path'

const reactDependencies = {
  react: '19.3.0-canary-fef12a01-20260413',
  'react-dom': '19.3.0-canary-fef12a01-20260413',
}

// This test only applies to Turbopack
;(!process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'turbopack unsupported features log',
  () => {
    describe('no config', () => {
      const { next } = nextTestSetup({
        files: path.join(__dirname, 'fixtures/no-config'),
        dependencies: reactDependencies,
      }

ut).not.toContain(
          'You are using configuration and/or tools that are not yet'
        )
      })
    })

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

)

      it('should not warn by default', async () => {
        const html = await next.render('/')
        expect(html).toContain('hello world')
        expect(next.cliOutput).toContain('(Turbopack)')
        expect(next.cliOutp


renderViaHTTP } from 'next-test-utils'

describe('Prerender crawler handling', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/index.js': `
        export default function Page() {
          return
index page

        }
      `,
      'pages/blog/[slug].js': `
        import {useRouter} from 'next/router'

        export default function Page({ slug }) {
          const router = useRouter()

          if (router.isFallback) {
            return 'Loading...'

params }) {
          return {
            props: {
              slug: params.slug
            }
          }
        }

        export async function getStaticPaths() {
          return {
            paths: ['/blog/first'],
            fallback:

}

          return (
            <>

slug page

{slug}

            </>
          )
        }

        export async function getStaticProps({


t/data/${next.buildId}/blog/post-4.json`,
      initialExpireSeconds: 31536000,
      initialRevalidateSeconds: 10,
      srcRoute: '/blog/[post]',
    },
    '/blog/post-1/comment-1': {
      allowHeader,
      dataRoute: `/_next/data/${next.buildId}/blog/post-1/comment-1.json`,
      initialExpireSeconds: 31536000,
      initialRevalidateSeconds: 2,
      srcRoute: '/blog/[post]/[comment]',
    },
    '/blog/post-2/comment-2': {
      allowHeader,
      dataRoute: `/_next/data/${next.buildId}/blog/post-2/

g/post.1.json`,
      initialExpireSeconds: 31536000,
      initialRevalidateSeconds: 10,
      srcRoute: '/blog/[post]',
    },
    '/catchall-explicit/another/value': {
      allowHeader,
      dataRoute: `/_next/data/${next.buildId}/catchall-explicit/an

comment-2.json`,
      initialExpireSeconds: 31536000,
      initialRevalidateSeconds: 2,
      srcRoute: '/blog/[post]/[comment]',
    },
    '/blog/post.1': {
      allowHeader,
      dataRoute: `/_next/data/${next.buildId}/blo


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

describe('Scroll Back Restoration Support', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      react: '19.3.0-canary-fef12a01-20260413',
      'react-dom': '19.3.0-canary-fef12a01-20260413',
    },
    // Vercel deployment fails to build/deploy this fixture in CI; skip in deploy mode.
    skipDeployment: true,
  })

  it('should restore the scroll position on navigating back', async () => {
    const browser =

ect(scrollRestoration).toBe('manual')

    const scrollX = Math.floor(await browser.eval(() => window.scrollX))
    const scrollY = Math.floor(await browser.eval(() => window.scrollY))

    expect(scrollX).not.toBe(0)
    expect(scrollY).not.toBe(0)

    a

await next.browser('/')
    await browser.eval(() =>
      document.querySelector('#to-another').scrollIntoView()
    )
    const scrollRestoration = await browser.eval(
      () => window.history.scrollRestoration
    )

    exp