extStart } = nextTestSetup({
    files: __dirname,
    // Assertions don't apply to deploy mode (output differs vs. local Next.js server).
    skipDeployment: true,
  })

  const urlPaths = [
    '%2Fmy-post%2F',
    '%252Fmy-post%252F',
    '%2Bmy-post%2B',
    '%3Fmy-post%3F',
    '%26my-post%26',
    encodeURIComponent('商業日語'),
    encodeURIComponent(encodeURIComponent('商業日語')),
    '%20my-post%20',
    '%2Fsecond-post%2F',
    '%2Bsecond-post%2B',
    '%26second-post%26',
    `mixed-${encodeURIComponent

F',
    '+second-post+',
    '&second-post&',
    'mixed-商業日語',
  ]

  const modePaths = ['fallback-blocking', 'fallback-false', 'fallback-true']

  if (isNextStart) {
    it('should output paths correctly', async () => {
      const pagesDir = join(next.t

('商業日語')}`,
  ]

  const prerenderedPaths = [
    '%2Fmy-post%2F',
    '%252Fmy-post%252F',
    '+my-post+',
    '%3Fmy-post%3F',
    '&my-post&',
    '商業日語',
    encodeURIComponent('商業日語'),
    ' my-post ',
    '%2Fsecond-post%2


tRequest } from 'next/server'
import { Streamable } from '../../streamable'

export const runtime = 'edge'

let streamable: ReturnType<typeof Streamable> | undefined

export async function GET(req: NextRequest): Promise<Response> {
  if (req.nextUrl.searchParams.has('compile')) {
    // The request just wants to trigger compilation.
    return new Response(null, { status: 204 })
  }

  // Consume the entire request body.
  // This is so we don't confuse the request close with the connection close.
  await r

  s.abort()
      return new Response(null, { status: 204 })
    }

    req.signal.onabort = () => {
      s.abort()
    }

    return new Response(s.stream)
  }

  // The 2nd request should render the stats. We don't use a query param
  // because edge re

eq.text()

  const write = req.nextUrl.searchParams.get('write')

  if (write) {
    const s = (streamable = Streamable(+write))

    // The request was aborted before the response was returned.
    if (req.signal.aborted) {


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

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

  useEffect(() => {
    window.hashChangeStart = 'no'
    window.hashChangeComplete = 'no'
    const hashChangeStart = () => {
      window.hashChangeStart = 'yes'
    }
    const hashChangeComplete = () => {
      window.hashChangeComplete = 'yes'
    }

    router.events.on('hashChangeStart', hashChangeStart)
    router.events.on('hashChangeComplet

"props-locale">{props.locale}

{router.locale}

      <Link
        href={{ pathname: router.pathname, query: router.query, hash: '#hash' }}
        locale={router.locale === 'fr' ? 'en' : 'fr'}
        id="change-locale"

e', hashChangeComplete)

    return () => {
      router.events.off('hashChangeStart', hashChangeStart)
      router.events.off('hashChangeComplete', hashChangeComplete)
    }
  }, [router.events])

  return (
    <>
      <p id=


k from 'next/link'
import { useRouter } from 'next/router'

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

{router.asPath}

      <Lin

"to-index">
        to /
      </Link>
      <br />
    </>
  )
}

export const getStaticProps = ({ locale, locales }) => {
  if (locale === 'en' || locale === 'nl') {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      locale,


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

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

  return (
    <>

developments page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathn

}

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

    </>
  )
}

export const getServerSideProps = ({ locale, locales, defaultLocale }) => {
  return {
    props: {
      locale,
      locales,
      defaultLocale,
    },


ailingSlashTrue, getFiles } from './utils'
import { FileRef, isNextStart, nextTestSetup, PatchedFileRef } from 'e2e-utils'

describe('app dir - with output export', () => {
  if (isNextStart) {
    describe('with exportPathMap configured', () => {
      let { next } = nextTestSetup({
        files: {
          app: new FileRef(join(__dirname, '..', 'app')),
          'next.config.js': new PatchedFileRef(
            join(__dirname, '..', 'next.config.js'),
            (content) =>
              content.repl

)

      it('should throw', async () => {
        let { exitCode, cliOutput } = await next.build()
        expect(exitCode).toBe(1)
        expect(cliOutput).toContain(
          'The "exportPathMap" configuration cannot be used with the "app" directory. P

ace(
                'trailingSlash: true,',
                `trailingSlash: true,
       exportPathMap: async function (map) {
        return map
      },`
              )
          ),
        },
        skipStart: true,
      }


rom 'next/router'

const Page = () => {
  const router = useRouter()
  const { query } = router
  return (
    <>
      <Link href="#only-hash" id="dynamic-route-only-hash">
        Dynamic route only hash
      </Link>

      <Link href={{ hash: 'only-hash-obj' }} id="dynamic-route-only-hash-obj">
        Dynamic route only hash object
      </Link>

      <Link href="?name=post-2" id="dynamic-route-only-query">
        Dynamic route only query
      </Link>

      <Link

"dynamic-route-only-query-obj"
      >
        Dynamic route only query object
      </Link>
      <br />
      <Link
        href={{ query: { name: 'post-5', another: 'value' } }}
        id="dynamic-route-only-query-obj-extra"
      >
        Dynamic rou

        href="?name=post-3&another=value"
        id="dynamic-route-only-query-extra"
      >
        Dynamic route only query extra
      </Link>
      <br />
      <Link
        href={{ query: { name: 'post-4' } }}
        id=


 *  4. Wait for the MCP HTTP server to be ready.
 *  5. Run MCP HTTP and CLI queries and verify the response structure.
 */
import { nextTestSetup, isNextDeploy } from 'e2e-utils'
import { existsSync } from 'fs'
import path from 'path'
import spawn from 'cross-spawn'
import type { ChildProcess } from 'child_process'
import treeKill from 'tree-kill'
import { findPort, retry } from 'next-test-utils'

// ─── helpers ─────────────────────────────────────────────────────────────────

const nextBin = path.join(

e
 * first `data:` line that contains a `result.content[].text` field.
 */
async function callMcpTool(
  port: number,
  toolName: string,
  args: Record<string, unknown>
): Promise<string> {
  const res = await fetch(`http://127.0.0.1:${port}/mcp`, {

 path.dirname(require.resolve('next/package')),
  'dist/bin/next'
)

/**
 * POST a JSON-RPC `tools/call` to the MCP server and return the text content.
 * The Streamable-HTTP transport responds with Server-Sent Events; we find th


rt path from 'path'
import fs from 'fs-extra'

function extractJSON(response) {
  return JSON.parse(response.headers.get('data') ?? '{}')
}

function baseNextConfig(): Parameters<typeof nextTestSetup>[0] {
  return {
    files: {
      'src/add.wasm': new FileRef(path.join(__dirname, './add.wasm')),
      'src/add.js': `
          import wasm from './add.wasm?module'
          const instance$ = WebAssembly.instantiate(wasm);

          export async function increment(a) {
            const { exports } = awa

 increment } from './src/add.js'
          export default async function middleware(request) {
            const input = Number(request.nextUrl.searchParams.get('input')) || 1;
            const value = await increment(input);
            return new Respon

it instance$;
            return exports.add_one(a);
          }
        `,
      'pages/index.js': `
          export default function () { return
Hello, world!
 }
        `,
      'middleware.js': `
          import {


 { nextTestSetup, isNextDev, isNextStart } from 'e2e-utils'

describe('Errors on conflict between public file and page file', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  if (isNextDev) {
    it('should show conflict error during development', async () => {
      await next.start()

      const regex = /A conflicting public file and page file was found for path/

      const conflicts = ['/another/confl

    it('should show conflict error during build', async () => {
      const { cliOutput } = await next.build()
      const conflicts = ['/another/conflict', '/another', '/hello']

      expect(cliOutput).toMatch(/Conflicting public and page files were foun

ict', '/hello']
      for (const conflict of conflicts) {
        const html = await next.render(conflict)
        expect(html).toMatch(regex)
      }

      expect(next.cliOutput).toMatch(regex)
    })
  }

  if (isNextStart) {


ed) return

  it('should apply temporary redirect when visited directly for GSSP page', async () => {
    const res = await next.fetch(`${basePath}/gssp-blog/redirect-1`, {
      redirect: 'manual',
    })
    expect(res.status).toBe(307)

    const { pathname } = new URL(res.headers.get('location')!)
    expect(pathname).toBe(`${basePath}/404`)
  })

  it('should apply temporary redirect when visited directly basePath false for GSSP page', async () => {
    const res = await next.fetch(
      `${basePath}/

)!)
    expect(parsedUrl.pathname).toBe(`/404`)

    const browser = await next.browser(`${basePath}`)
    await browser.eval(`next.router.push('/gssp-blog/redirect-1-no-basepath-')`)
    await retry(async () => {
      const html = await browser.eval('doc

gssp-blog/redirect-1-no-basepath-`,
      { redirect: 'manual' }
    )
    expect(res.status).toBe(307)

    const text = await res.text()
    expect(text).toEqual(`/404`)

    const parsedUrl = new URL(res.headers.get('location'


Router } from 'next/router'

export default function Post(props) {
  const router = useRouter()

  if (typeof window === 'undefined') {
    if (router.query.post?.startsWith('redir')) {
      console.log(router)
      throw new Error('render should not occur for redirect')
    }
  }

  return (
    <>

getServerSideProps

{JSON.stringify(props)}

    </>
  )
}

export const getServerSideProps = ({ params }) => {
  if (params.post.startsWith('redir')) {
    let des

, '/')
    }

    let permanent = undefined
    let statusCode = undefined

    if (params.post.includes('statusCode-')) {
      statusCode = parseInt(
        params.post.split('statusCode-').pop().split('-').shift(),
        10
      )
    }

    if (par

tination = '/404'

    if (params.post.includes('dest-external')) {
      destination = 'https://example.vercel.sh'
    } else if (params.post.includes('dest-')) {
      destination = params.post.split('dest-').pop().replace(/_/g


'next/router'

export default function Post(props) {
  const router = useRouter()

  if (typeof window === 'undefined') {
    if (router.query.post?.startsWith('redir')) {
      console.log(router)
      throw new Error('render should not occur for redirect')
    }
  }

  if (typeof window !== 'undefined' && !window.initialHref) {
    window.initialHref = window.location.href
  }

  if (router.isFallback) return
Loading...

  return (
    <>

getStaticProps

{

 'https://example.vercel.sh'
    } else if (params.post.includes('dest-')) {
      destination = params.post.split('dest-').pop().replace(/_/g, '/')
    }

    let permanent = undefined
    let statusCode = undefined

    if (params.post.includes('statusCo

JSON.stringify(props)}</p>
    </>
  )
}

export const getStaticProps = ({ params }) => {
  if (params.post.startsWith('redir')) {
    let destination = '/404'

    if (params.post.includes('dest-external')) {
      destination =


y).isNextDeploy) {
    it('should skip deploy', () => {})
    return
  }

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

  let backend: http.Server
  let backendPort: number
  let intermediary: http.Server
  let intermediaryPort: number
  const backendRequests: string[] = []

  async function sendSmugglingPayload({
    nextPort,
    connectionHeader,
    method = 'DELETE',
    rewritePath = '/rewrites/poc',
  }: {
    nextPort: number
    connectionHeader: string
    met

  `${smuggledRequest.length.toString(16).toUpperCase()}\r\n`,
      'latin1'
    )

    const payload = Buffer.concat([
      Buffer.from(
        `${method} ${rewritePath} HTTP/1.1\r\nHost: 127.0.0.1:${nextPort}\r\nTransfer-Encoding: chunked\r\nConnection

hod?: 'DELETE' | 'OPTIONS'
    rewritePath?: string
  }) {
    const smuggledRequest = Buffer.from(
      `GET /secret HTTP/1.1\r\nHost: 127.0.0.1:${nextPort}\r\n\r\n`,
      'latin1'
    )
    const chunkSize = Buffer.from(


import { nextTestSetup } from 'e2e-utils'

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

  // Recommended for tests that check HTML. Cheerio is a HTML parser that has a jQuery like API.
  it('should work using cheerio', async () => {
    const $ = await next.render$('/')
    expect($('p').text()).toBe('hello world')
  })

  // Recommended for tests that need a full browser
  it('should work using browser', async () => {
    const browser = await next.browser('/'

r('/')
    expect(html).toContain('hello world')
  })

  // In case you need to test the response object
  it('should work with fetch', async () => {
    const res = await next.fetch('/')
    const html = await res.text()
    expect(html).toContain('hello

)
    expect(await browser.elementByCss('p').text()).toBe('hello world')
  })

  // In case you need the full HTML. Can also use $.html() with cheerio.
  it('should work with html', async () => {
    const html = await next.rende

test/e2e/test-template/{{ toFileName name }}/{{ toFileName name }}.test.ts


cHeader = 'X-From-Src-Middleware'
const rootHeader = 'X-From-Root-Middleware'

describe('middleware-src', () => {
  const { next, isTurbopack, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  if (isNextDev) {
    beforeAll(async () => {
      await next.start()
    })
  }

  describe('Middleware in src/ folder', () => {
    if (isNextDev) {
      it('loads and runs src middleware', async () => {
        const response = await next

rt', async () => {
        await next.patchFile(
          'next.config.js',
          "module.exports = { output: 'export' }"
        )
        await next.build()
        expect(next.cliOutput).toContain(
          'Statically exporting a Next.js applicat

.fetch('/post-1')
        expect(response.headers.has(srcHeader)).toBe(false)
        expect(response.headers.has(`${srcHeader}-TS`)).toBe(true)
      })
    }

    if (!isNextDev) {
      it('should warn about middleware on expo


 isNextDev, isNextStart } from 'e2e-utils'
import { findPort, initNextServerScript, killApp } from 'next-test-utils'

describe('Fetch polyfill with ky-universal', () => {
  ;(isNextDev ? describe : describe.skip)('development mode', () => {
    const { next } = nextTestSetup({
      files: __dirname,
      skipStart: true,
      dependencies: { 'ky-universal': '0.6.0', ky: '0.19.1' },
    })

    let apiServerPort: number
    let apiServer: any

    beforeAll(async () => {
      const scriptPath = join(__di

r: options is not defined/
      )

      next.env.NEXT_PUBLIC_API_PORT = String(apiServerPort)
      await next.start()
    })

    afterAll(async () => {
      await killApp(apiServer)
    })

    it('includes polyfilled fetch when using getStaticProps (

rname, 'api-server.js')
      apiServerPort = await findPort()
      apiServer = await initNextServerScript(
        scriptPath,
        /ready on/i,
        { ...process.env, PORT: String(apiServerPort) },
        /ReferenceErro


'
import path from 'path'
import { promises as fs } from 'fs'
import { readJson } from 'fs-extra'

describe('Edge Compiler can import asset assets', () => {
  const { next, isTurbopack, isNextDeploy } = nextTestSetup({
    files: path.join(__dirname, './app'),
  })

  it('allows to fetch a remote URL', async () => {
    const response = await fetchViaHTTP(next.url, '/api/edge', {
      handler: 'remote-full',
    })
    expect(await response.text()).toContain('Example Domain')
  })

  it('allows to fetch a

it('allows to fetch text assets', async () => {
    const html = await renderViaHTTP(next.url, '/api/edge', {
      handler: 'text-file',
    })
    expect(html).toContain('Hello, from text-file.txt!')
  })

  it('allows to fetch image assets', async () =>

remote URL with a path and basename', async () => {
    const response = await fetchViaHTTP(next.url, '/api/edge', {
      handler: 'remote-with-base',
    })
    expect(await response.text()).toContain('Example Domain')
  })


 const config = { runtime: 'edge' }

/**
 * @param {import('next/server').NextRequest} req
 */
export default async (req) => {
  const handlerName = req.nextUrl.searchParams.get('handler')
  const handler = handlers.get(handlerName) || defaultHandler
  return handler()
}

/**
 * @type {Map<string, () => Promise<Response>>}
 */
const handlers = new Map([
  [
    'text-file',
    async () => {
      const url = new URL('../../src/text-file.txt', import.meta.url)
      return fetch(url)
    },
  ],
  [
    'im

, import.meta.url)
      return fetch(url)
    },
  ],
  [
    'remote-full',
    async () => {
      const url = new URL('https://example.vercel.sh')
      return fetch(url)
    },
  ],
  [
    'remote-with-base',
    async () => {
      const url = new U

age-file',
    async () => {
      const url = new URL('../../src/vercel.png', import.meta.url)
      return fetch(url)
    },
  ],
  [
    'from-node-module',
    async () => {
      const url = new URL('my-pkg/hello/world.json'


emporary redirect when visited directly for GSSP page', async () => {
    const res = await next.fetch('/gssp-blog/redirect-1', {
      redirect: 'manual',
    })
    expect(res.status).toBe(307)

    const { pathname } = new URL(res.headers.get('location')!)
    expect(pathname).toBe('/404')
  })

  it('should apply permanent redirect when visited directly for GSSP page', async () => {
    const res = await next.fetch('/gssp-blog/redirect-permanent', {
      redirect: 'manual',
    })
    expect(res.status

ed directly for GSSP page', async () => {
    const res = await next.fetch('/gssp-blog/redirect-statusCode-301', {
      redirect: 'manual',
    })
    expect(res.status).toBe(301)

    const { pathname } = new URL(res.headers.get('location')!)
    expect(

).toBe(308)

    const { pathname } = new URL(res.headers.get('location')!)
    expect(pathname).toBe('/404')
    expect(res.headers.get('refresh')).toMatch(/url=\/404/)
  })

  it('should apply statusCode 301 redirect when visit


etch').default
  // @ts-expect-error
  global.Request = require('node-fetch').Request
  // @ts-expect-error
  global.Headers = require('node-fetch').Headers
}

const { readFileSync } = require('fs')

/** @type {import('next').default} */
// @ts-ignore: missing interopDefault
const next = require('next')

const { join } = require('path')
const { parse } = require('url')
const getPort = require('get-port')

const dev = process.env.NODE_ENV !== 'production'
const dir = __dirname
const useHttps = process.env.US

process.on('unhandledRejection', (err) => {
  console.error('unhandledRejection:', err)
})

async function main() {
  const envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 0
  const port = envPort > 0 ? envPort : await getPort()
  const host

E_HTTPS === 'true'
const { createServer } = require(useHttps ? 'https' : 'http')

const httpOptions = {
  key: readFileSync(join(__dirname, 'ssh/localhost-key.pem')),
  cert: readFileSync(join(__dirname, 'ssh/localhost.pem')),
}


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

  const locales = ['en-US', 'nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en']

  it('should load the index route correctly SSR', async () => {
    const res = await next.fetch('/', { redirect: 'manual' })
    expect(res.status).toBe(200)

    const $ = await next.render$('/')

    expect($('#router-locale').text()).toBe('en-US')
    expect($('#router-default-locale').text()).toBe('en-US')
    expect($('#router-pathname').text()).toBe(

arse($('#router-locales').text())).toEqual(locales)
  })

  it('should load the index route correctly CSR', async () => {
    const browser = await next.browser('/')

    expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
    expect(

'/[[...slug]]')
    expect($('#router-as-path').text()).toBe('/')
    expect(JSON.parse($('#props').text())).toEqual({
      params: {},
      locale: 'en-US',
      locales,
      defaultLocale: 'en-US',
    })
    expect(JSON.p


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

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

  return (
    <>

catch-all page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}</p

to /another
      </Link>

      <Link href="/" locale="nl-NL" id="to-locale-index">
        to /nl-nl
      </Link>

      <Link href="/another" locale="nl-NL" id="to-locale-another">
        to /nl-nl/another
      </Link>

>

{router.asPath}

      <Link href="/" locale="en-US" id="to-def-locale-index">
        to /
      </Link>

      <Link href="/another" locale="en-US" id="to-def-locale-another">


rChunkUrlPath,
} from 'next-test-utils'

describe('Client 404', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    // Assertions don't apply to deploy mode (output differs vs. local Next.js server).
    skipDeployment: true,
  })
  if (skipped) return

  beforeAll(async () => {
    // pre-build the home page so that navigating to it from the
    // error page doesn't time out while webpack compiles on demand
    await next.render('/')
  })

  describe('should show 404 upon client

  // In webpack dev mode, compiling the home page (via the
      // `next.render('/')` pre-build in beforeAll) can race with the
      // `/asd` page's hydration and trigger a Fast Refresh-driven full
      // reload, which in turn swallows the click on `#

replacestate', () => {
    it('should navigate the page', async () => {
      const browser = await next.browser('/asd')
      const serverCode = await browser
        .waitForElementByCss('#errorStatusCode')
        .text()


lementByCss('#link-other')
        const titleColor = await browser.eval(() => {
          const el = document.querySelector('#link-other')
          return el ? window.getComputedStyle(el).backgroundColor : ''
        })
        expect(titleColor).toBe('rgb(0, 255, 0)')
      }

      async function checkPinkButton(browser: Playwright) {
        await browser.elementByCss('#link-index')
        const titleColor = await browser.eval(() => {
          const el = document.querySelector('#link-index')

owser = await next.browser('/')
        try {
          await checkGreenButton(browser)
        } finally {
          await browser.close()
        }
      })

      it('should have correct color on index page (on hover)', async () => {
        const brows

  return el ? window.getComputedStyle(el).backgroundColor : ''
        })
        expect(titleColor).toBe('rgb(255, 105, 180)')
      }

      it('should have correct color on index page (on load)', async () => {
        const br


ort fs from 'fs/promises'
import { nextTestSetup } from 'e2e-utils'

describe('externals-transitive', () => {
  const { next, isTurbopack, isNextDeploy, isNextStart } = nextTestSetup({
    files: __dirname,
    dependencies: require('./package.json').dependencies,
  })

  it('uses the right version of transitive externals', async () => {
    const $ = await next.render$('/')
    const body = $('body > p').text().trim()
    expect(body).toEqual(`depA: 3.10.1, depB: 4.17.21, 4.17.21, 5.0.0`)

    if (!isNextD

s) {
        const content = await next.readFile(
          path.join(next.distDir, 'server', file)
        )
        isLodashBundled =
          isLodashBundled ||
          // Code
          content.includes('__lodash_hash_undefined__') ||
          // p

eploy) {
      const files = glob.sync('**/*.js', {
        cwd: path.join(next.testDir, next.distDir, 'server'),
      })
      let isLodashBundled = false
      let isStorybookGlobalBundled = false
      for (const file of file


tTestSetup } from 'e2e-utils'

describe('i18n-navigations-middleware', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should respect selected locale when navigating to a dynamic route', async () => {
    const browser = await next.browser('/')
    // change to "de" locale
    await browser.elementByCss("[href='/de']").click()
    const dynamicLink = await browser.waitForElementByCss(
      "[href='/de/dynamic/1']"
    )
    expect(await browser.elementById('current-locale').tex

e: de'
    )
  })

  it('should respect selected locale when navigating to a static route', async () => {
    const browser = await next.browser('/')
    // change to "de" locale
    await browser.elementByCss("[href='/de']").click()
    const staticLink =

t()).toBe(
      'Current locale: de'
    )

    // navigate to dynamic route
    await dynamicLink.click()

    // the locale should still be "de"
    expect(await browser.elementById('dynamic-locale').text()).toBe(
      'Local


test-utils'

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

  it('hydrates correctly for normal page', async () => {
    const browser = await next.browser('/')
    expect(await browser.eval('window.didHydrate')).toBe(true)
  })

  it('hydrates correctly for //', async () => {
    const browser = await next.browser('//')
    expect(await browser.eval('window.didHydrate')).toBe(true)
  })

  it('should be able to navigate after loading //', async () => {
    cons

er.eval('window.beforeNav = true')
    await browser.eval('window.next.router.push("/details")')
    await retry(async () => {
      const html = await browser.eval('document.documentElement.innerHTML')
      expect(html).toMatch(/details/)
    })
    expe

t browser = await next.browser('//')
    await brows


ocales } from '../i18n-support/shared'
import { findPort, fetchViaHTTP } from 'next-test-utils'
import { nextTestSetup, isNextDev, type NextInstance } from 'e2e-utils'

type BrowserOptions = Parameters<NextInstance['browser']>[1]

describe('i18n Support basePath', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  const ctx: Record<string, any> = {
    basePath: '/docs',
    isDev: isNextDev,
    browser: (pa

er = http.createServer((req, res) => {
      res.statusCode = 200
      res.end(JSON.stringify({ url: req.url, external: true }))
    })
    await new Promise<void>((resolve, reject) => {
      externalServer.listen(externalPort, (err?: Error) =>
        e

thname: string, options?: BrowserOptions) =>
      next.browser(pathname, options),
  }

  let externalServer: http.Server
  let externalPort: number

  beforeAll(async () => {
    externalPort = await findPort()
    externalServ


   // localeDetection: false,
    locales: [
      'nl-NL',
      'nl-BE',
      'nl',
      'fr-BE',
      'fr',
      'en-US',
      'en',
      'go',
      'go-BE',
      'do',
      'do-BE',
    ],
    defaultLocale: 'en-US',
    domains: [
      {
        http: true,
        domain: 'example.do',
        defaultLocale: 'do',
        locales: ['do-BE'],
      },
      {
        domain: 'example.com',
        defaultLocale: 'go',
        locales: ['go-BE'],
      },
    ],
  },
  async redirects() {

se',
        permanent: false,
        locale: false,
      },
      {
        source: '/redirect-3',
        destination: '/somewhere-else',
        permanent: false,
      },
      {
        source: '/redirect-4',
        destination: '/',
        perman

return [
      {
        source: '/en-US/redirect-1',
        destination: '/somewhere-else',
        permanent: false,
        locale: false,
      },
      {
        source: '/nl/redirect-2',
        destination: '/somewhere-el


ink from 'next/link'
import { useRouter } from 'next/router'

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

  return (
    <>

another page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.

sPath}

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

    </>
  )
}

export const getServerSideProps = ({ locale, locales, defaultLocale }) => {
  return {
    props: {
      locale,
      locales,
      defaultLocale,


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

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

  return (
    <>

frank page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname

<Link href="/gsp/fallback/first" id="to-fallback-first">
        to /gsp/fallback/first
      </Link>

      <Link href="/gsp/fallback/hello" id="to-fallback-hello">
        to /gsp/fallback/hello
      </Link>

      <Link href

}

{router.asPath}

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

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


rom 'next/router'
import { useEffect } from 'react'
import { useState } from 'react'

export default function Page(props) {
  const router = useRouter()
  const parsedAs = new URL(router.asPath, 'http://n')
  const [asPath, setAsPath] = useState(parsedAs.pathname)

  useEffect(() => {
    if (router.isReady && router.asPath && asPath !== router.asPath) {
      setAsPath(router.asPath)
    }
  }, [router.asPath, router.isReady, asPath])

  return (
    <>

index page

      <p id="props

main-locales">{JSON.stringify(router.domainLocales)}

{JSON.stringify(router.query)}

{router.pathname}

{asPath}

      <Link href="/another" id="to-another"

">{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

      <p id="router-do


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

export default function Page(props) {
  const router = useRouter()
  const { nextLocale } = router.query

  return (
    <>

links page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

      <p id="router-p

ocale} id="to-gsp">
        to /gsp
      </Link>

      <Link
        href="/gsp/fallback/first"
        locale={nextLocale}
        id="to-fallback-first"
      >
        to /gsp/fallback/first
      </Link>

      <Link
        h

athname">{router.pathname}

{router.asPath}

      <Link href="/another" locale={nextLocale} id="to-another">
        to /another
      </Link>

      <Link href="/gsp" locale={nextL


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

export default function Page(props) {
  const router = useRouter()
  const { nextLocale } = router.query

  return (
    <>

links page

{JSON.stringify(props)}

{router.locale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

{ro

</Link>

      <Link
        href={`/${nextLocale}/gsp/fallback/first`}
        locale={false}
        id="to-fallback-first"
      >
        to /gsp/fallback/first
      </Link>

      <Link
        href={`/${nextLocale}/gsp/fallb

uter.asPath}

      <Link href={`/${nextLocale}/another`} locale={false} id="to-another">
        to /another
      </Link>

      <Link href={`/${nextLocale}/gsp`} locale={false} id="to-gsp">
        to /gsp


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

  return (
    <>

links page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

{router.asPath}

s">
        to /gsp
      </Link>

      <Link href="/gsp" locale="nl-NL" id="to-gsp-nl-nl">
        to /gsp
      </Link>

      <Link href="/gsp" locale="fr" id="to-gsp-fr">
        to /gsp
      </Link>

      <Lin

<Link href="/gsp" locale="en-US" id="to-gsp-en-u


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

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

  return (
    <>

gssp page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

  <Link href="/" id="to-index">
        to /
      </Link>
      <br />
    </>
  )
}

export const getServerSideProps = ({
  params,
  locale,
  locales,
  defaultLocale,
}) => {
  return {
    props: {
      params,
      locale,
      locales,
      def


  <Link href="/" id="to-index">
        to /
      </Link>
      <br />
    </>
  )
}

export const getServerSideProps = ({
  locale,
  locales,
  defaultLocale,
  query,
}) => {
  return {
    props: {
      query,
      locale,
      locales,
      defau


t Link from 'next/link'
import { useRouter } from 'next/router'

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathn

}

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

    </>
  )
}

export const getStaticProps = ({ locale, locales, defaultLocale }) => {
  return {
    props: {
      locale,
      locales,
      defaultLocale,
    },
  }
}


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

describe('nonce head manager', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'app/pages')),
      public: new FileRef(join(__dirname, 'app/public')),
    },
  })

  async function runTests(url) {
    const browser = await next.browser(url)
    await check(
      async () =>
        await browser.eval(`JSON.stringify(window.scriptExecutionIds)`),
      '["src-1.js"

 =>
        await browser.eval(`JSON.stringify(window.scriptExecutionIds)`),
      '["src-1.js"]'
    )

    await browser.elementByCss('#change-script').click()
    await check(
      async () =>
        await browser.eval(`JSON.stringify(window.scriptExe

]'
    )

    await browser.elementByCss('#force-rerender').click()
    await check(
      async () =>
        await browser.eval(`document.getElementById('h1').textContent`),
      'Count 1'
    )
    await check(
      async ()


from 'e2e-utils'
import { expectVaryHeaderToContain } from 'next-test-utils'
import path from 'path'

describe('Vary Header Tests', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, '../app'),
    skipDeployment: true,
  })

  it('should preserve custom vary header in API routes', async () => {
    const res = await next.fetch('/api/custom-vary')
    expectVaryHeaderToContain(res.headers.get('vary'), ['custom-header'])
  })

  it('should preserve custom vary header and append RSC he

   expect(res.headers.get('cache-control')).toBe('s-maxage=3600')

    // Next.js internal headers are appended
    expectVaryHeaderToContain(varyHeader, [
      'rsc',
      'next-router-state-tree',
      'next-router-prefetch',
    ])
  })

  it('should

aders in app route handlers', async () => {
    const res = await next.fetch('/normal')
    const varyHeader = res.headers.get('vary')

    // Custom header is preserved
    expectVaryHeaderToContain(varyHeader, ['user-agent'])


import React from 'react'
import Link from 'next/link'
import { useCallback, useRef, useEffect, useState } from 'react'
import { flushSync } from 'react-dom'

export default function Page() {
  const [isVisible, setIsVisible] = useState(true)

  const statusRef = useRef({ wasInitialized: false, wasCleanedUp: false })

  const refWithCleanup = useCallback((el) => {
    if (!el) {
      console.error(
        'callback refs that returned a cleanup should never be called with null'
      )
      return
    }

IsVisible(false)
        })
        if (!statusRef.current.wasInitialized) {
          console.error('callback ref was not initialized')
        }
        if (!statusRef.current.wasCleanedUp) {
          console.error('callback ref was not cleaned up')

    statusRef.current.wasInitialized = true
    return () => {
      statusRef.current.wasCleanedUp = true
    }
  }, [])

  useEffect(() => {
    const timeout = setTimeout(
      () => {
        flushSync(() => {
          set


 { FileRef, nextTestSetup } from 'e2e-utils'
import { renderViaHTTP, fetchViaHTTP } from 'next-test-utils'
import path from 'path'
import cheerio from 'cheerio'
const appDir = path.join(__dirname, 'app')

// TODO: This test needs to check multiple files and syntax features.
describe.skip('Browserslist', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(path.join(appDir, 'pages')),
      // In Chrome 45 arrow functions are introduced, by
      '.browserslistrc': 'Chrome 42',

    .toArray()
            .map(async (el) => {
              const src = $(el).attr('src')
              const res = await fetchViaHTTP(next.url, src)
              const code = await res.text()
              if (code.includes('async ()=>')) {

  },
  })

  it('should apply browserslist target', async () => {
    const html = await renderViaHTTP(next.url, '/')
    const $ = cheerio.load(html)

    expect(
      (
        await Promise.all(
          $('script')


m Server $title', ({ title, useHttps }) => {
  // The HTTPS server presents a self-signed certificate that the test process
  // does not trust. Pass a custom agent that skips cert verification on every
  // HTTPS request. Setting `process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'`
  // does not take effect from inside the Jest VM context.
  const agent =
    useHttps === 'true'
      ? new https.Agent({ rejectUnauthorized: false })
      : undefined

  describe('with dynamic assetPrefix', () => {
    const {

    skipDeployment: true,
      disableAutoSkewProtection: true,
    })
    if (skipped) return

    it('should serve internal file from render', async () => {
      const html = await next.render('/static/hello.txt', undefined, { agent })
      expect(htm

next, skipped } = nextTestSetup({
      files: __dirname,
      startCommand: 'node server.js',
      serverReadyPattern: /- Local:/,
      env: { USE_HTTPS: useHttps, NODE_ENV: sharedNodeEnv },
      dependencies: sharedDeps,


f */
export function invokeNodeAPI(useCase) {
  let handle
  if (useCase === 'Buffer') {
    Buffer.from('')
  } else if (useCase === 'setImmediate') {
    handle = setImmediate(() => {})
  } else if (useCase === 'clearImmediate') {
    clearImmediate(handle)
  } else if (useCase === 'process.cwd') {
    console.log(process.cwd())
  } else if (useCase === 'process.getuid') {
    console.log(process.getuid())
  } else if (useCase === 'process.cpuUsage') {
    console.log(process.cpuUsage())
  } else if (useC

else if (useCase === 'CountQueuingStrategy') {
    new CountQueuingStrategy()
  } else if (useCase === 'DecompressionStream') {
    new DecompressionStream()
  } else if (useCase === 'DomException') {
    new DomException()
  } else if (useCase === 'Messag

ase === 'BroadcastChannel') {
    new BroadcastChannel()
  } else if (useCase === 'ByteLengthQueuingStrategy') {
    new ByteLengthQueuingStrategy()
  } else if (useCase === 'CompressionStream') {
    new CompressionStream()
  }


port { nextTestSetup, isNextDev, isNextStart } from 'e2e-utils'
;((isNextDev && process.env.TURBOPACK_BUILD) ||
  (isNextStart && process.env.TURBOPACK_DEV)
  ? describe.skip
  : describe)('Catches Missing getStaticProps', () => {
  const errorRegex = /getStaticPaths was added without a getStaticProps in/

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

  if (isNextDev) {
    it('should catch it in development mode', async () => {
      co

it next.render('/hello')
      expect(html).toMatch(errorRegex)
    })
  }

  if (isNextStart) {
    it('should catch it in server build mode', async () => {
      const { cliOutput } = await next.build()
      expect(cliOutput).toMatch(errorRegex)
    })


it.skip)

const isModeDeploy = process.env.NEXT_TEST_MODE === 'deploy'

describe('Middleware custom matchers', () => {
  if ((global as any).isNextDeploy && process.env.TEST_NODE_MIDDLEWARE) {
    return it('should skip deploy for now', () => {})
  }

  const { next } = nextTestSetup({
    files: new FileRef(join(__dirname, '../app')),
    overrideFiles: process.env.TEST_NODE_MIDDLEWARE
      ? {
          'middleware.js': new FileRef(
            join(__dirname, '../app/middleware-node.js')
          ),

')).toBeDefined()

      const res2 = await fetchViaHTTP(next.url, '/missing-match-1', undefined, {
        headers: {
          hello: 'world',
        },
      })
      expect(res2.headers.get('x-from-middleware')).toBeFalsy()

      const res3 = await f

      }
      : {},
  })

  const runTests = () => {
    it('should match missing header correctly', async () => {
      const res = await fetchViaHTTP(next.url, '/missing-match-1')
      expect(res.headers.get('x-from-middleware


rom 'next/server'

export default function middleware(request) {
  const res = NextResponse.rewrite(new URL('/', request.url))
  res.headers.set('X-From-Middleware', 'true')
  return res
}

export const config = {
  runtime: 'nodejs',
  matcher: [
    { source: '/source-match' },
    {
      source: '/has-match-1',
      has: [
        {
          type: 'header',
          key: 'x-my-header',
          value: '(?<myHeader>.*)',
        },
      ],
    },
    {
      source: '/has-match-2',
      has: [

ue)',
        },
      ],
    },
    {
      source: '/has-match-4',
      has: [
        {
          type: 'host',
          value: 'example.com',
        },
      ],
    },
    {
      source: '/has-match-5',
      has: [
        {
          type: 'heade

    {
          type: 'query',
          key: 'my-query',
        },
      ],
    },
    {
      source: '/has-match-3',
      has: [
        {
          type: 'cookie',
          key: 'loggedIn',
          value: '(?<loggedIn>tr


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

const locales = ['', '/en', '/sv', '/nl']

describe('i18n-ignore-redirect-source-locale with basepath', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'app/pages')),
    },
    dependencies: {},
    nextConfig: {
      basePath: '/basepath',
      i18n: {
        locales: ['en', 'sv', 'nl'],
        defaultLocale: 'en',
      },
      async redirects() {
        return [
          {

,
            permanent: false,
            locale: false,
          },
          {
            source: '/:locale/to-slash',
            destination: '/newpage',
            permanent: false,
            locale: false,
          },
          {

     source: '/:locale/to-sv',
            destination: '/sv/newpage',
            permanent: false,
            locale: false,
          },
          {
            source: '/:locale/to-en',
            destination: '/en/newpage'


isNextDev } from 'e2e-utils'

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

  it('should resolve prefetch promise', async () => {
    const browser = await next.browser('/')
    const text = await browser
      .elementByCss('#prefetch-button')
      .click()
      .waitForElementByCss('#hidden-until-click')
      .text()
    expect(text).toBe('visible')
    await browser.close()
  })

  if (isNextDev) {
    it('should not prefetch in development', async

const browser = await next.browser('/')
      const links = await browser
        .elementByCss('#prefetch-button')
        .click()
        .elementsByCss('link[rel=prefetch]')

      expect(links.length).toBe(0)
      await browser.close()
    })
  }
})


est-utils'
import path from 'path'
import type { Response } from 'node-fetch'

async function serialize(response: Response) {
  return {
    text: await response.text(),
    headers: Object.fromEntries(response.headers),
    status: response.status,
  }
}

describe('Edge can read request body', () => {
  const { next } = nextTestSetup({
    files: new FileRef(path.resolve(__dirname, './app')),
    dependencies: {},
  })

  it('renders the static page', async () => {
    const html = await renderViaHTTP(next

-handler=json',
        null,
        {
          method: 'POST',
          body: JSON.stringify({ hello: 'world' }),
        }
      )
      expect(await serialize(response)).toMatchObject({
        text: expect.stringContaining('ok'),
        status: 200

.url, '/api/nothing')
    expect(html).toContain('ok')
  })

  describe('middleware', () => {
    it('reads a JSON body', async () => {
      const response = await fetchViaHTTP(
        next.url,
        '/api/nothing?middleware


import { nextTestSetup, isNextDev, isNextStart } from 'e2e-utils'
;((isNextDev && process.env.TURBOPACK_BUILD) ||
  (isNextStart && process.env.TURBOPACK_DEV)
  ? describe.skip
  : describe)('Custom routes', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should rewrite and render page correctly', async () => {
    const html = await next.render('/docs/hello')
    expect(html).toMatch(/hello world/)
  })

  it('should rewrite to /_next/static correctly', async () => {
    const

st data = await next.render('/docs/static/data.json')
    expect(data).toContain('some data...')
  })

  it('should rewrite to public file correctly', async () => {
    const data = await next.render('/docs/another.txt')
    expect(data).toContain('some te

bundlePath = `/docs/_next/static/${next.buildId}/_buildManifest.js`
    const data = await next.render(bundlePath)
    expect(data).toContain('/hello')
  })

  it('should rewrite to public/static correctly', async () => {
    con


nextConfig = {
  reactStrictMode: true,
  rewrites: async () => {
    return {
      beforeFiles: [
        {
          source: '/',
          destination: '/foo',
        },
        {
          source: '/rewrite-to-another-segment/:id',
          destination: '/rewrite-to-another-segment/:id/foo',
        },
        // Even though there's rewrite, below won't work as expected due to trade-off.
        {
          source: '/rewrite-to-same-segment/1',
          destination: '/rewrite-to-same-segment/001',

ame-segment/2',
          destination: '/rewrite-to-same-segment/002',
        },
        {
          source: '/rewrite-to-same-segment/3',
          destination: '/rewrite-to-same-segment/003',
        },
      ],
    }
  },
}

module.exports = nextConfig

       },
        {
          source: '/rewrite-to-s


mport { nextTestSetup } from 'e2e-utils'

describe('Custom routes i18n with index redirect', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    // Assertions don't apply to deploy mode (output differs vs. local Next.js server).
    skipDeployment: true,
  })
  if (skipped) return

  it('should respond to default locale redirects correctly for index redirect', async () => {
    for (const [path, dest] of [
      ['/', '/destination'],
      ['/en', '/destination'],
      ['/fr', '/

ext).toEqual(dest)
        if (dest.startsWith('/')) {
          const parsed = new URL(res.headers.get('location'))
          expect(parsed.pathname).toBe(dest)
          expect(parsed.search).toBe('')
        } else {
          expect(res.headers.get('lo

fr/destination'],
    ]) {
      const res = await next.fetch(path, {
        redirect: 'manual',
      })

      expect(res.status).toBe(dest ? 307 : 404)

      if (dest) {
        const text = await res.text()
        expect(t


ort React from 'react'
import Script from 'next/script'

const Page = () => {
  const [counter, setCounter] = React.useState(0)
  const [scriptURL, toggleScriptSource] = React.useReducer(
    (currentScriptURL, id) => {
      const scriptSource =
        typeof currentScriptURL === 'string'
          ? currentScriptURL
          : currentScriptURL.pathname
      if (scriptSource === '/src-1.js') {
        return new URL(`/src-2.js?key=${Math.random()}`, window.location)
      } else {
        return new URL

e="abc123" src={scriptSource} />

{'Count ' + counter}

      <button id="force-rerender" onClick={() => setCounter(counter + 1)}>
        Re-render
      </button>
      <button id="change-script" onClick={toggleScriptSource}>

(`/src-1.js?key=${Math.random()}`, window.location)
      }
    },
    '/src-1.js'
  )
  const scriptSource =
    typeof scriptURL === 'string' ? scriptURL : scriptURL.href

  return (
    <>
      <Script key={scriptSource} nonc


import React, { useCallback, useEffect, useRef, useState } from 'react'
import Link from 'next/link'

const useClickAway = (ref, onClickAway) => {
  useEffect(() => {
    const handler = (event) => {
      const el = ref.current

      // when menu is open and clicked inside menu, A is expected to be false
      // when menu is open and clicked outside menu, A is expected to be true
      console.log('A', el && !el.contains(event.target))

      el && !el.contains(event.target) && onClickAway(event)
    }

removeEventListener('click', handler)
    }
  }, [onClickAway, ref])
}

export default function App() {
  const [open, setOpen] = useState(false)

  const menuRef = useRef(null)

  const onClickAway = useCallback(() => {
    console.log('click away, open',

    let timeoutID = setTimeout(() => {
      timeoutID = null
      document.addEventListener('click', handler)
    }, 0)

    return () => {
      if (timeoutID != null) {
        clearTimeout(timeoutID)
      }
      document.


 { FileRef, nextTestSetup } from 'e2e-utils'
import { renderViaHTTP, fetchViaHTTP } from 'next-test-utils'
import path from 'path'
import cheerio from 'cheerio'
const appDir = path.join(__dirname, 'app')

// TODO: This test needs to check multiple files and syntax features.
describe.skip('default browserslist target', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(path.join(appDir, 'pages')),
    },
  })

  it('should apply default browserslist target', async () => {
    co

= $(el).attr('src')
              const res = await fetchViaHTTP(next.url, src)
              const code = await res.text()
              // Default compiles for ES Modules output
              if (code.includes('async ()=>')) {
                return src

nst html = await renderViaHTTP(next.url, '/')
    const $ = cheerio.load(html)

    expect(
      (
        await Promise.all(
          $('script')
            .toArray()
            .map(async (el) => {
              const src


rom 'e2e-utils'
import { join } from 'path'

describe('postcss-config-json', () => {
  const { next } = nextTestSetup({
    files: new FileRef(join(__dirname, 'app')),
    dependencies: {
      autoprefixer: '10.4.19',
      postcss: '8.4.38',
      tailwindcss: '3.4.4',
    },
    packageJson: {
      postcss: {
        plugins: {
          tailwindcss: {},
          autoprefixer: {},
        },
      },
    },
  })

  it('works with postcss config specified in package.json', async () => {
    let browser

 = await browser.elementByCss('.text-6xl').text()
      expect(text).toMatch(/Welcome to/)
      const cssBlue = await browser
        .elementByCss('#test-link')
        .getComputedCss('color')
      expect(cssBlue).toBe('rgb(37, 99, 235)')
    } finally

= await next.browser('/')
    try {
      const text


rom 'next/server'

export default function middleware(request) {
  const res = NextResponse.rewrite(new URL('/', request.url))
  res.headers.set('X-From-Middleware', 'true')
  return res
}

export const config = {
  matcher: [
    { source: '/source-match' },
    {
      source: '/has-match-1',
      has: [
        {
          type: 'header',
          key: 'x-my-header',
          value: '(?<myHeader>.*)',
        },
      ],
    },
    {
      source: '/has-match-2',
      has: [
        {
          type:

  ],
    },
    {
      source: '/has-match-4',
      has: [
        {
          type: 'host',
          value: 'example.com',
        },
      ],
    },
    {
      source: '/has-match-5',
      has: [
        {
          type: 'header',
          key: 'h

 'query',
          key: 'my-query',
        },
      ],
    },
    {
      source: '/has-match-3',
      has: [
        {
          type: 'cookie',
          key: 'loggedIn',
          value: '(?<loggedIn>true)',
        },


tTestSetup, isNextDev, isNextDeploy } from 'e2e-utils'

const installCheckVisible = (browser) => {
  return browser.eval(`(function() {
      window.checkInterval = setInterval(function() {
      const root = document.querySelector('nextjs-portal').shadowRoot;
      const statusElement = root.querySelector('[data-indicator-status]')
      const badge = root.querySelector('[data-next-badge]')
      const status = badge ? badge.getAttribute('data-status') : null

      // Check if we're showing any build/comp

escribe('Build Activity Indicator', () => {
  // Use describe.skip so that this suite does not fail with "no tests" during deploy tests.
  ;(isNextDeploy ? describe.skip : describe)('Invalid position config', () => {
    const { next } = nextTestSetup({

ile status
      window.showedBuilder = window.showedBuilder || (
        statusElement !== null || (status && status !== 'none')
      )
      if (window.showedBuilder) clearInterval(window.checkInterval)
    }, 5)
  })()`)
}

d


mport { FileRef, nextTestSetup } from 'e2e-utils'

jest.setTimeout(2 * 60 * 1000)

export function runTests(
  example = '',
  testPath = '/',
  expectedContent = ['index page']
) {
  const versionParts = process.versions.node.split('.').map((i) => Number(i))

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

  if (
    versionParts[0] > 16 ||
    (versionParts[0] === 16 && versionParts[1] >= 14)
  ) {
    const srcDir = join(__dirname, '../../../../exa

 the install, we also need to fulfill the peerDependencies.
    // However, the example specified latest next which may have different peerDependencies that the next that we test here i.e. the next on this commit.
    delete packageJson.dependencies['react

mples', example)
    const srcFiles = fs.readdirSync(srcDir)

    const packageJson = fs.readJsonSync(join(srcDir, 'package.json'))
    // Use the default versions that are usually used in tests.
    // Since we replace `next` in


sNextDev, isNextStart } from 'e2e-utils'
import { BUILD_ID_FILE, BUILD_MANIFEST } from 'next/constants'

describe('distDir', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })
  if (skipped) return

  it('should render the page', async () => {
    const html = await next.render('/')
    expect(html).toMatch(/Hello World/)
  })

  it('should build the app within the given `dist` directory', async () => {
    if (isNextDev) {
      expect(await next.hasFil

ect(await next.hasFile('.next')).toBe(false)
  })
})

if (isNextStart) {
  describe('distDir config validation', () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      skipStart: true,
      skipDeployment: true,
    })
    if

e(`dist/dev/${BUILD_MANIFEST}`)).toBe(true)
    } else {
      expect(await next.hasFile(`dist/${BUILD_ID_FILE}`)).toBe(true)
    }
  })

  it('should not build the app within the default `.next` directory', async () => {
    exp


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

describe('Link ref app', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  const noError = async (pathname: string) => {
    const browser = await next.browser('/')
    await browser.eval(`(function() {
      window.caughtErrors = []
      const origError = window.console.error
      window.console.error = function (format) {
        window.caughtErrors.push(format)
        origError(arguments)
      }
      window.next.router.re

name: string) => {
    const requests: string[] = []
    const browser = await next.browser(pathname, {
      beforePageLoad(page: any) {
        page.on('request', async (req: any) => {
          const url = new URL(req.url())
          const headers = aw

place('${pathname}')
    })()`)
    await retry(async () => {
      const errors = await browser.eval(`window.caughtErrors`)
      expect(errors).toEqual([])
    })
    await browser.close()
  }

  const didPrefetch = async (path


v className="flex flex-col items-center justify-center min-h-screen py-2">

          Welcome to{' '}

            Next.js!

          Get started by editing{' '}
          <code className="p-3 font-mono text-

g/docs"
            className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
          >

Documentation →

              Fi

lg bg-gray-100 rounded-md">
            pages/index.js
          </code>
        </p>

        <div className="flex flex-wrap items-center justify-around max-w-4xl mt-6 sm:w-full">
          <a
            href="https://nextjs.or


-check

import { NextResponse } from 'next/server'

/**
 * @param {NextRequest} req
 */
export default async function middleware(req) {
  const res = NextResponse.next()
  res.headers.set('x-incoming-content-type', req.headers.get('content-type'))

  const handler =
    bodyHandlers[req.nextUrl.searchParams.get('middleware-handler')]
  const headers = await handler?.(req)
  for (const [key, value] of headers ?? []) {
    res.headers.set(key, value)
  }

  return res
}

/**
 * @typedef {import('next/server')

 [
      ['x-req-type', 'json'],
      ['x-serialized', JSON.stringify(json)],
    ]
  },
  text: async (req) => {
    const text = await req.text()
    return [
      ['x-req-type', 'text'],
      ['x-serialized', text],
    ]
  },
  formData: async (req)

.NextRequest} NextRequest
 * @typedef {(req: NextRequest) => Promise<[string, string][]>} Handler
 * @type {Record<string, Handler>}
 */
const bodyHandlers = {
  json: async (req) => {
    const json = await req.json()
    return


m 'next/dist/compiled/strip-ansi'

const unsupportedFunctions = [
  'setImmediate',
  'clearImmediate',
  'process.cwd',
  'process.cpuUsage',
  'process.getuid',
]
const undefinedProperties = ['process.arch', 'process.version']
const unsupportedClasses = [
  'BroadcastChannel',
  'ByteLengthQueuingStrategy',
  'CompressionStream',
  'CountQueuingStrategy',
  'DecompressionStream',
  'DomException',
  'MessageChannel',
  'MessageEvent',
  'MessagePort',
  'ReadableByteStreamController',
  'ReadableStreamBYO

({
    files: __dirname,
    // Turbopack builds fail (non-zero exit) when edge code uses Node.js APIs,
    // but the CLI output still contains the warnings we're asserting on. Skip
    // the automatic start so we can run the build manually and ignore th

BRequest',
  'ReadableStreamDefaultController',
  'TransformStreamDefaultController',
  'WritableStreamDefaultController',
]

describe('Edge runtime with Node.js APIs', () => {
  const { next, isNextDev, skipped } = nextTestSetup


r-with-rewrites', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should preserve current pathname when using useRouter.push with rewrites', async () => {
    const browser = await next.browser('/')
    await browser.elementById('router-push').click()

    const url = new URL(await browser.url())
    expect(url.pathname + url.search).toBe('/?param=1')
  })

  it('should preserve current pathname when using useRouter.replace with rewrites', async () => {
    const browser = await

ing Link with rewrites', async () => {
    const browser = await next.browser('/')
    await browser.elementByCss('a').click()

    const url = new URL(await browser.url())
    expect(url.pathname + url.search).toBe('/?param=1')
  })

  describe('rewrite t

 next.browser('/')
    await browser.elementById('router-replace').click()

    const url = new URL(await browser.url())
    expect(url.pathname + url.search).toBe('/?param=1')
  })

  it('should preserve current pathname when us


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

const locales = ['', '/en', '/sv', '/nl']

describe('i18n-ignore-redirect-source-locale', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'app/pages')),
    },
    dependencies: {},
    nextConfig: {
      i18n: {
        locales: ['en', 'sv', 'nl'],
        defaultLocale: 'en',
      },
      async redirects() {
        return [
          {
            source: '/:locale/to-sv',

 locale: false,
          },
          {
            source: '/:locale/to-slash',
            destination: '/newpage',
            permanent: false,
            locale: false,
          },
          {
            source: '/:locale/to-same',
            des

destination: '/sv/newpage',
            permanent: false,
            locale: false,
          },
          {
            source: '/:locale/to-en',
            destination: '/en/newpage',
            permanent: false,


scribe('Preview mode with fallback pages', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      cookie: '0.7.2',
    },
  })

  let previewCookie: string

  it('should get preview cookie correctly', async () => {
    const res = await next.fetch('/api/enable')
    previewCookie = ''

    expect(res.headers.get('set-cookie')).toMatch(
      /(__prerender_bypass|__next_preview_data)/
    )

    res.headers
      .get('set-cookie')!
      .split(',')
      .forEach((c) =>

`${
            isBypass ? '__prerender_bypass' : '__next_preview_data'
          }=${cookies[isBypass ? '__prerender_bypass' : '__next_preview_data']}`
        }
      })
  })

  it('should not write preview index SSG page to cache', async () => {
    con

{
        const cookies = cookie.parse(c)
        const isBypass = cookies.__prerender_bypass

        if (isBypass || cookies.__next_preview_data) {
          if (previewCookie) previewCookie += '; '

          previewCookie +=


bsocket',
          destination:
            'http://localhost:__EXTERNAL_PORT__/_next/hmr?page=/about',
        },
        {
          source: '/websocket-to-page',
          destination: '/hello',
        },
        {
          source: '/to-nowhere',
          destination: 'http://localhost:12233',
        },
        {
          source: '/rewriting-to-auto-export',
          destination: '/auto-export/hello?rewrite=1',
        },
        {
          source: '/rewriting-to-another-auto-export/:path*',

   },
        {
          source: '/hello-world',
          destination: '/static/hello.txt',
        },
        {
          source: '/',
          destination: '/another',
        },
        {
          source: '/another',
          destination: '/multi-r

      destination: '/auto-export/another?rewrite=1',
        },
        {
          source: '/to-another',
          destination: '/another/one',
        },
        {
          source: '/nav',
          destination: '/404',


from 'next/link'

const Page = () => (
  <>

Nav

    <Link href="/hello" as="/first" id="to-hello">
      to hello
    </Link>

    <Link href="/hello-again" as="/second" id="to-hello-again">
      to hello-again
    </Link>

    <Link
      href={{
        pathname: '/with-params',
        query: {
          something: 1,
          another: 'value',
        },
      }}
      as="/params/1?another=value"
      id="to-params-manual"
    >
      to params (manual)

br />
    <Link href="/hello?overrideMe=1" id="to-overridden">
      to /hello?overrideMe=1
    </Link>

    <Link href="/old-blog/about" id="to-old-blog">
      to /old-blog/post-1
    </Link>

    <Link href="/overridden" id="to-befor

</Link>

    <Link href="/params/1?another=value" id="to-params">
      to params
    </Link>

    <Link href="/rewriting-to-auto-export" id="to-rewritten-dynamic">
      to rewritten dynamic
    </Link>
    <


port { ImageResponse } from 'next/og'
import fs from 'fs'
import path from 'path'

export async function GET() {
  const font = await fs.promises.readFile(
    // We need to use process.cwd() instead of import.meta.url for nft tracing purpose
    path.join(process.cwd(), 'assets/typewr__.ttf')
  )
  return new ImageResponse(
    (
      <div
        style={{
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',

 88,
          background: '#fff',
          color: '#000',
        }}
      >
        Typewriter og
      </div>
    ),
    {
      fonts: [
        {
          name: 'Typewriter',
          data: font,
          style: 'normal',
        },
      ],
    }


'
import { retry, waitFor } from 'next-test-utils'

// Eviction requires the dev server (HMR) and persistent caching (Turbopack).
// Skip entirely in prod/start mode.
;(isNextDev ? describe : describe.skip)('evict-after-snapshot', () => {
  const envVars = [
    'ENABLE_CACHING=1',
    'TURBO_ENGINE_IGNORE_DIRTY=1',
    'TURBO_ENGINE_SNAPSHOT_IDLE_TIMEOUT_MILLIS=1000',
    'TURBO_ENGINE_EVICT_AFTER_SNAPSHOT=1',
  ].join(' ')

  const { skipped, next } = nextTestSetup({
    files: __dirname,
    skipDeployme

otAndEviction() {
    // The idle timeout is 1s, give extra time for snapshot + eviction to complete
    await waitFor(5000)
  }

  // Turbopack-only: eviction requires persistent caching
  ;(process.env.IS_TURBOPACK_TEST ? it : it.skip)(
    'should serve

nt: true,
    packageJson: {
      scripts: {
        dev: `${envVars} next dev`,
      },
    },
    installCommand: 'npm i',
    startCommand: 'npm run dev',
  })

  if (skipped) {
    return
  }

  async function waitForSnapsh


  return 0
  }
  let totalSize = 0
  const entries = await fs.readdir(dirPath, {
    recursive: true,
    withFileTypes: true,
  })
  for (const entry of entries) {
    if (entry.isFile()) {
      const filePath = path.join(entry.parentPath ?? entry.path, entry.name)
      const stat = await fs.stat(filePath)
      totalSize += stat.size
    }
  }
  return totalSize
}

for (const cacheEnabled of [false, true]) {
  describe(`filesystem-caching with cache ${cacheEnabled ? 'enabled' : 'disabled'}`, () => {

  // Make it easier to run in development, test directories are cleared between runs already so this is safe.
      `TURBO_ENGINE_IGNORE_DIRTY=1`,
      // decrease the idle timeout to make the test more reliable
      `TURBO_ENGINE_SNAPSHOT_IDLE_TIMEOUT_M

 beforeAll(() => {
      process.env.NEXT_PUBLIC_ENV_VAR = 'hello world'
    })
    afterAll(() => {
      delete process.env.NEXT_PUBLIC_ENV_VAR
    })

    let envVars = [
      `ENABLE_CACHING=${cacheEnabled ? '1' : ''}`,


enableCaching = !!process.env.ENABLE_CACHING

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  turbopack: {
    rules: {
      './app/**/page.{jsx,tsx}': {
        loaders: ['./my-timestamp-loader.js'],
      },
      './app/loader/page.tsx': {
        loaders: ['./my-loader.js'],
      },
      './pages/pages.tsx': {
        loaders: ['./my-timestamp-loader.js'],
      },
    },
  },
  experimental: {
    turbopackFileSystemCacheForBuild: enableCaching,
    turbopackFileSystemCacheForDev

ader.js'],
    })
    config.module.rules.push({
      test: /app\/loader(?:\/client)?\/page\.tsx/,
      use: ['./my-loader.js'],
    })
    if (enableCaching) {
      config.cache = Object.freeze({
        type: 'memory',
      })
    }
    if (dev) {

: enableCaching,
  },
  env: {
    NEXT_PUBLIC_CONFIG_ENV: 'hello world',
  },
  webpack(config, { dev }) {
    config.module.rules.push({
      test: /app(?:\/.*)?\/page\.[tj]sx|pages\/pages\.tsx/,
      use: ['./my-timestamp-lo


 cycle, run a warm
// cycle and snapshot the set of turbo-tasks functions that had any cache
// miss. If a task previously cached (e.g. via a persistable entries map)
// regresses to recomputing on warm restart, this snapshot will change and
// fail the test.
//
// When the snapshot moves:
//   - FEWER entries → that's a win. Run with `-u` and commit the new snapshot.
//   - MORE entries → something is recomputing on warm start. Investigate
//                    before updating.
//
// Dev and start (build)

, TaskFunctionStatistics>

const STATS_RELATIVE_PATH = '.next/warm-restart-task-stats.json'

;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
  'warm-restart task statistics',
  () => {
    const env = [
      'ENABLE_CACHING=1',
      'TURBO_E

snapshots are kept separate because the warm graphs
// differ: dev brings up HMR/Fast Refresh infra that build doesn't.

interface TaskFunctionStatistics {
  cache_hit: number
  cache_miss: number
}
type TaskStats = Record<string


            source: '/add-header',
            headers: [
              {
                key: 'x-hello',
                value: 'world',
              },
            ],
          },
          {
            source: '/add-header-no-basepath',
            basePath: false,
            headers: [
              {
                key: 'x-hello',
                value: 'world',
              },
            ],
          },
        ]
      },
    },
  })

  it('should navigate to external site and back', async () =

click()
      .waitForElementByCss('input', { state: 'attached' })
      .back()
      .waitForElementByCss('p')

    await waitFor(1000)
    const newText = await browser.elementByCss('p').text()
    expect(newText).toBe('server')
  })

  if (process.env.

> {
    const browser = await next.browser(`${basePath}/external-and-back`)
    const initialText = await browser.elementByCss('p').text()
    expect(initialText).toBe('server')

    await browser
      .elementByCss('a')
      .


etup({
    files: __dirname,
    nextConfig: {
      basePath,
      onDemandEntries: {
        // Make sure entries are not getting disposed.
        maxInactiveAge: 1000 * 60 * 60,
      },
    },
  })

  describe('client-side navigation', () => {
    it('should navigate to /404 correctly client-side', async () => {
      const browser = await next.browser(`${basePath}/slug-1`)
      await check(
        () => browser.eval('document.documentElement.innerHTML'),
        /slug-1/
      )

      await browse

Be(`${basePath}/slug-2`)
    })

    it('should navigate to /_error correctly client-side', async () => {
      const browser = await next.browser(`${basePath}/slug-1`)
      await check(
        () => browser.eval('document.documentElement.innerHTML'),

r.eval('next.router.push("/404", "/slug-2")')
      await check(
        () => browser.eval('document.documentElement.innerHTML'),
        /page could not be found/
      )
      expect(await browser.eval('location.pathname')).to


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

describe('basePath query/hash handling', () => {
  const basePath = '/docs'
  const { next } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      basePath,
      onDemandEntries: {
        // Make sure entries are not getting disposed.
        maxInactiveAge: 1000 * 60 * 60,
      },
    },
  })

  it.each([
    { hash: '#hello?' },
    { hash: '#?' },
    { hash: '##' },
    { hash: '##?' },
    { hash: '##hello?' },
    { hash: '##hello'

)(
    'is correct during query updating $hash $search',
    async ({ hash, search, query }) => {
      const browser = await next.browser(
        `${basePath}${search || ''}${hash || ''}`
      )

      await check(
        () =>
          browser.eval('

 },
    { hash: '#hello?world' },
    { search: '?hello=world', hash: '#a', query: { hello: 'world' } },
    { search: '?hello', hash: '#a', query: { hello: '' } },
    { search: '?hello=', hash: '#a', query: { hello: '' } },
  ]


'

describe('basePath', () => {
  const basePath = '/docs'

  const { next, isNextDeploy } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      basePath,
      onDemandEntries: {
        // Make sure entries are not getting disposed.
        maxInactiveAge: 1000 * 60 * 60,
      },
      async rewrites() {
        return [
          {
            source: '/rewrite-1',
            destination: '/gssp',
          },
          {
            source: '/rewrite-no-basepath',
            destination: 'h

,
            destination: '/gssp',
          },
        ]
      },

      async redirects() {
        return [
          {
            source: '/redirect-1',
            destination: '/somewhere-else',
            permanent: false,
          },

ttps://example.vercel.sh',
            basePath: false,
          },
          {
            source: '/rewrite/chain-1',
            destination: '/rewrite/chain-2',
          },
          {
            source: '/rewrite/chain-2'


-utils'

describe('basePath', () => {
  const basePath = '/docs'

  const { next } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      basePath,
      onDemandEntries: {
        // Make sure entries are not getting disposed.
        maxInactiveAge: 1000 * 60 * 60,
      },
    },
  })

  it('should use urls with basepath in router events', async () => {
    const browser = await next.browser(`${basePath}/hello`)
    try {
      await retry(() =>
        expect(browser.eval('window.next.router.is

t eventLog = await browser.eval('window._getEventLog()')
      expect(
        eventLog.filter((item) => item[1]?.endsWith('/other-page'))
      ).toEqual([
        ['routeChangeStart', `${basePath}/other-page`, { shallow: false }],
        ['beforeHistory

Ready')).resolves.toBe(true)
      )
      await browser.eval('window._clearEventLog()')
      await browser
        .elementByCss('#other-page-link')
        .click()
        .waitForElementByCss('#other-page-title')

      cons


'basePath + trailingSlash', () => {
  const basePath = '/docs'

  const { next } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      trailingSlash: true,
      basePath,
      onDemandEntries: {
        // Make sure entries are not getting disposed.
        maxInactiveAge: 1000 * 60 * 60,
      },
    },
  })

  const runTests = (dev = false) => {
    it('should allow URL query strings without refresh', async () => {
      const browser = await next.browser(`${basePath}/hello/?query=true`)

s (see #13132, #13560)
          setTimeout(resolve, dev ? 10000 : 1000)
        })
        expect(await browser.eval('window.itdidnotrefresh')).toBe('hello')

        const pathname = await browser.elementByCss('#pathname').text()
        expect(pathname)

 try {
        await browser.eval('window.itdidnotrefresh = "hello"')
        await new Promise((resolve, reject) => {
          // Timeout of EventSource created in setupPing()
          // (on-demand-entries-utils.js) is 5000 m


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

// We use session storage for the event log so that it will survive
// page reloads, which happen for instance during routeChangeError
const EVENT_LOG_KEY = 'router-event-log'

function getEventLog() {
  const data = sessionStorage.getItem(EVENT_LOG_KEY)
  return data ? JSON.parse(data) : []
}

function clearEventLog() {
  sessionStorage.removeItem(EVENT_LOG_KEY)
}

function addEvent(data) {
  const eventLog = getEventLog()
  eventLog.push(data)
  sessionSto

g = getEventLog
}

function useLoggedEvent(event, serializeArgs = (...args) => args) {
  const router = useRouter()
  useEffect(() => {
    const logEvent = (...args) => {
      addEvent([event, ...serializeArgs(...args)])
    }
    router.events.on(event,

rage.setItem(EVENT_LOG_KEY, JSON.stringify(eventLog))
}

if (typeof window !== 'undefined') {
  // global functions introduced to interface with the test infrastructure
  window._clearEventLog = clearEventLog
  window._getEventLo


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

function Page() {
  const router = useRouter()
  const routerObj = router.isReady ? router : { pathname: '', asPath: '' }
  return (
    <>
      <Link href="/other-page" id="other-page-link">

Hello World

      </Link>

      <Link href="/gsp" id="gsp-link">

getStaticProps

      </Link>

      <Link href="/gssp" id="gssp-link">

getServerSideProps

      </Link>

      <Link href

catchall page

      </Link>

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

index getStaticProps

      </Link>

      <Link href="/index" id="nested-index-gsp">

nested index getStaticProps

      </Link>

="/[slug]" as="/first" id="dynamic-link">

dynamic page

      </Link>

      <Link
        href="/catchall/[...parts]"
        as="/catchall/hello/world"
        id="catchall-link"
      >


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

export const getStaticProps = () => {
  return {
    props: {
      nested: false,
      hello: 'hello',
    },
  }
}

export default function Index({ hello, nested }) {
  const { query, pathname, asPath } = useRouter()
  const [mounted, setMounted] = useState(false)
  useEffect(() => {
    setMounted(true)
    return () => setMounted(false)
  }, [])
  return (
    <>
      <h1 id="index-p

'yes' : 'no'}

{hello} world

{JSON.stringify(query)}

{pathname}

{mounted ? asPath : ''}

      <Link href="/hello" id="hello-link">
        to /hello


 skipDeployment: true,
  })

  const gip404Err =
    /`pages\/404` can not have getInitialProps\/getServerSideProps/

  it('should use pages/404', async () => {
    const html = await next.render('/abc')
    expect(html).toContain('custom 404 page')
  })

  it('should set correct status code with pages/404', async () => {
    const res = await next.fetch('/abc')
    expect(res.status).toBe(404)
  })

  it('should use pages/404 for .d.ts file', async () => {
    const html = await next.render('/invalidExtens

in('custom 404 page')
  })

  it('should render _error for a 500 error still', async () => {
    const html = await next.render('/err')
    expect(html).not.toContain('custom 404 page')
    expect(html).toContain(isNextDev ? 'oops' : 'Internal Server Error

ion')
    expect(html).toContain('custom 404 page')
  })

  it('should not error when visited directly', async () => {
    const res = await next.fetch('/404')
    expect(res.status).toBe(404)
    expect(await res.text()).toConta


using webpack.
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
  'postcss-config-ts',
  () => {
    describe('postcss.config.ts', () => {
      const { next } = nextTestSetup({
        files: new FileRef(join(__dirname, 'postcss-config')),
      })

      it('works with postcss.config.ts files', async () => {
        const browser = await next.browser('/')
        try {
          const text = await browser.elementByCss('#test').text()
          expect(text).toBe('Hello World')
          // The

test')
            .getComputedCss('color')
          expect(color).toBe('rgb(0, 128, 0)')
        } finally {
          await browser.close()
        }
      })
    })

    describe('.postcssrc.ts', () => {
      const { next } = nextTestSetup({
        f

CSS has `color: red` but the PostCSS plugin transforms it to green.
          // If this is green, it proves the TypeScript PostCSS config was loaded and applied.
          const color = await browser
            .elementByCss('#


\\.json$`
    ),
    page: '/blog',
  },
  {
    namedDataRouteRegex: `^/_next/data/${escapeRegex(
      buildId
    )}/blog/(?<nxtPpost>[^/]+?)\\.json$`,
    dataRouteRegex: normalizeRegEx(
      `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog\\/([^\\/]+?)\\.json$`
    ),
    page: '/blog/[post]',
    routeKeys: {
      nxtPpost: 'nxtPpost',
    },
  },
  {
    namedDataRouteRegex: `^/_next/data/${escapeRegex(
      buildId
    )}/blog/(?<nxtPpost>[^/]+?)/(?<nxtPcomment>[^/]+?)\\.json$`,
    dataRouteRe

mment: 'nxtPcomment',
    },
  },
  {
    namedDataRouteRegex: `^/_next/data/${escapeRegex(
      buildId
    )}/catchall/(?<nxtPpath>.+?)\\.json$`,
    dataRouteRegex: normalizeRegEx(
      `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/catchall\\/(.+?)\\.

gex: normalizeRegEx(
      `^\\/_next\\/data\\/${escapeRegex(
        buildId
      )}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$`
    ),
    page: '/blog/[post]/[comment]',
    routeKeys: {
      nxtPpost: 'nxtPpost',
      nxtPco


react-dom/server'
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime'
import { useRouter } from 'next/router'

function RouterComp(props) {
  const router = useRouter()

  if (!router) {
    throw new Error('router is missing!')
  }

  return (
    <>

props {JSON.stringify(props)}

router: {JSON.stringify(router)}

    </>
  )
}

export async function getServerSideProps({ req, query, preview }) {
  // this ensures the same router context is used by the

w: preview,
        }}
      >

hello world

        <RouterComp hello={'world'} />
      </RouterContext.Provider>
    )
  )
  return {
    props: {
      url: req.url,
      world: 'world',
      time: new Date().getTime(),
    },
  }
}

con

useRouter hook
  // no matter where it is imported
  console.log(
    ReactDOM.renderToString(
      <RouterContext.Provider
        value={{
          query,
          pathname: '/',
          asPath: req.url,
          isPrevie


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

export async function getServerSideProps({ params, query }) {
  return {
    world: 'world',
    query: query || {},
    params: params || {},
    time: new Date().getTime(),
    random: Math.random(),
  }
}

export default ({ world, time, params, random, query }) => {
  return (
    <>

hello: {world}

      time: {time}

{random}

{JSON.str

{JSON.stringify(query)}

{JSON.stringify(useRouter().query)}

      <Link href="/" id="home">
        to home
      </Link>

      <Link href="/another" id="another">
        to another
      </Link>
    </>
  )


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

export async function getServerSideProps({ params, query, resolvedUrl }) {
  return {
    props: {
      resolvedUrl: resolvedUrl,
      world: 'world',
      query: query || {},
      params: params || {},
      time: new Date().getTime(),
      random: Math.random(),
    },
  }
}

export default ({
  world,
  time,
  params,
  random,
  query,
  appProps,
  resolvedUrl,
}) => {
  const router = useRouter()

  return

iv id="query">{JSON.stringify(router.query)}

{JSON.stringify(appProps.query)}

{appProps.url}

{resolvedUrl}

{router.asPath}

(
    <>

hello: {world}

      time: {time}

{random}

{JSON.stringify(params)}

{JSON.stringify(query)}

      <d


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

export async function getServerSideProps({ params, resolvedUrl }) {
  if (params.post === 'post-10') {
    await new Promise((resolve) => {
      setTimeout(() => resolve(), 1000)
    })
  }

  if (params.post === 'post-100') {
    throw new Error('such broken..')
  }

  return {
    props: {
      params,
      resolvedUrl,
      post: params.post,
      time: (await import('perf_hooks')).performance.now(),
    },

/div>

{JSON.stringify(router.query)}

{JSON.stringify(appProps.query)}

{appProps.url}

{resolvedUrl}

{router.

}
}

export default ({ post, time, params, appProps, resolvedUrl }) => {
  const router = useRouter()

  return (
    <>

Post: {post}

      time: {time}

{JSON.stringify(params)}<


ware')
  })

  it('adds the header for a matched data path (with header)', async () => {
    const response = await fetchViaHTTP(
      next.url,
      `/_next/data/${next.buildId}/with-middleware.json`,
      undefined,
      { headers: { 'x-nextjs-data': '1' } }
    )
    expect(await response.json()).toMatchObject({
      pageProps: {
        message: 'Hello, cruel world.',
      },
    })
    expect(response.headers.get('X-From-Middleware')).toBe('true')
  })

  it('adds the header for a matched data pa

    message: 'Hello, cruel world.',
      },
    })
    expect(response.headers.get('X-From-Middleware')).toBe('true')
  })

  it('adds the header for another matched path', async () => {
    const response = await fetchViaHTTP(next.url, '/another-middlewa

th (without header)', async () => {
    const response = await fetchViaHTTP(
      next.url,
      `/_next/data/${next.buildId}/with-middleware.json`
    )
    expect(await response.json()).toMatchObject({
      pageProps: {


fetchViaHTTP } from 'next-test-utils'

describe('undici fetch', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/api/globalFetch.js': `
        import { ReadableStream } from 'node:stream/web';
        export default async function globalFetch(req, res) {
          try {
            const response = await fetch('https://example.vercel.sh')
            res.json({ value: response.body instanceof ReadableStream })
          } catch (error) {
            console.error(error);
            res

'entries'
          })
        }
      `,
      'pages/api/globalRequest.js': `
        export default async function globalRequest(req, res) {
          res.json({
            value: (new Request('https://example.vercel.sh')).headers[Symbol.iterator].name

.send(error);
          }
        }
      `,
      'pages/api/globalHeaders.js': `
        export default async function globalHeaders(req, res) {
          res.json({
            value: (new Headers())[Symbol.iterator].name ===


b/constants'

describe('GS(S)P Page Errors', () => {
  ;(isNextDev ? describe : describe.skip)('development mode', () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      skipDeployment: true,
    })
    if (skipped) return

    it('should show error for getStaticProps as component member', async () => {
      const outputIndex = next.cliOutput.length
      await next.patchFile(
        'pages/index.js',
        `
        const Page = () => 'hi'
        Page.getStaticProps = () =

t and must be exported from the page`
      )
    })

    it('should show error for getServerSideProps as component member', async () => {
      const outputIndex = next.cliOutput.length
      await next.patchFile(
        'pages/index.js',
        `

> ({ props: { hello: 'world' }})
        export default Page
      `
      )
      await next.render('/')
      expect(next.cliOutput.slice(outputIndex)).toContain(
        `getStaticProps can not be attached to a page's componen


sNextDev, isNextStart } from 'e2e-utils'
import stripAnsi from 'next/dist/compiled/strip-ansi'
import { retry } from 'next-test-utils'

describe('jsconfig.json baseurl', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })
  if (skipped) return

  describe('default behavior', () => {
    it('should render the page', async () => {
      const $ = await next.render$('/hello')
      expect($('body').text()).toMatch(/World/)
    })

    // Integration ran this

ld` below.
    ;(isNextDev ? it : it.skip)(
      'should have correct module not found error',
      async () => {
        const contents = await next.readFile('pages/hello.js')
        try {
          await next.patchFile(
            'pages/hello.js',

 under `launchApp` only. e2e splits dev vs `next start` jobs, so
    // `it.skip` when !isNextDev is correct: the module-not-found overlay is dev-only; production
    // jobs still cover `should trace correctly` under `should bui


 loader that returns invalid CSS with a source map.
// The source map points back to the original file, making it clear that the
// loader is responsible for the broken output (not the original source).
module.exports = function (source) {
  // Generate a source map that maps generated lines back to the original source.
  // The original file is valid CSS; the generated output is intentionally broken.
  //
  // Mapping (0-based line numbers):
  //   generated line 0 ("/* Generated by... */") -> original lin

        -> original line 2 ("  font-size: 16px;")
  //   generated line 4 ("  background: {{{...")   -> original line 1 ("  color: blue;")
  //   generated line 5 ("}")                      -> original line 3 ("}")
  const sourceMap = {
    version: 3,

e 0 (".page {")
  //   generated line 1 (".page {")               -> original line 0 (".page {")
  //   generated line 2 ("  color: red")           -> original line 1 ("  color: blue;")
  //   generated line 3 ("  @@@ ...")


tput.replaceAll(testDir + '/', '')
  const relMatch = testDir.match(/(test\/tmp\/next-test-[^/]+)/)
  if (relMatch) {
    result = result.replaceAll('./' + relMatch[1] + '/', './')
    result = result.replaceAll(relMatch[1] + '/', '')
  }
  return result
}

/**
 * Extracts a single error block from CLI output by searching for a title string.
 *
 * Start boundary: the nearest `⨯` marker (dev) or file-path line (prod)
 * before the title.
 * End boundary: the first blank line after an "Import trace" section t

n ''

  const beforeTitle = output.substring(0, titleIdx)

  // In dev mode, errors start with a `⨯` marker on the same line as the file path.
  // In prod mode, errors start with a bare file-path line above the title.
  const markerIdx = beforeTitle.lastI

hat
 * isn't followed by continuation content (indented lines or file paths).
 */
function extractErrorBlock(output: string, errorTitle: string): string {
  const titleIdx = output.indexOf(errorTitle)
  if (titleIdx === -1) retur


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

describe('router.isReady with appGip', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  const checkIsReadyValues = async (browser: any, expected: boolean[] = []) => {
    await retry(async () => {
      const values = JSON.stringify(
        (await browser.eval('window.isReadyValues')).sort()
      )
      expect(values).toBe(JSON.stringify(expected.sort()))
    })
  }

  it('isReady should be true immediately for

uery', async () => {
    const browser = await next.browser('/appGip?hello=world')
    await checkIsReadyValues(browser, [true])
  })

  it('isReady should be true immediately for getStaticProps page without query', async () => {
    const browser = await

 pages without getStaticProps', async () => {
    const browser = await next.browser('/appGip')
    await checkIsReadyValues(browser, [true])
  })

  it('isReady should be true immediately for pages without getStaticProps, with q


derChunkUrlPath,
  retry,
} from 'next-test-utils'

describe('Link ref forwarding', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  async function noError(pathname: string) {
    const browser = await next.browser('/')
    await browser.eval(`(function() {
      window.caughtErrors = []
      const origError = window.console.error
      window.console.error = function (format) {
        window.caughtErrors.push(format)
        origError(arguments)
      }
      window.next.router.re

name: string) {
    const browser = await next.browser(pathname)
    const chunk = getClientBuildManifestLoaderChunkUrlPath(next.testDir, '/')

    await retry(async () => {
      const links = await browser.elementsByCss('link[rel=prefetch]')
      const

place('${pathname}')
    })()`)
    await retry(async () => {
      const errors = await browser.eval(`window.caughtErrors`)
      expect(errors).toEqual([])
    })
    await browser.close()
  }

  async function didPrefetch(path


ls'

describe('404 Page Support SSG', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    disableAutoSkewProtection: true,
    // Assertions don't apply to deploy mode (output differs vs. local Next.js server).
    skipDeployment: true,
  })
  if (skipped) return

  it('should respond to 404 correctly', async () => {
    const res = await next.fetch('/404')
    expect(res.status).toBe(404)
    expect(await res.text()).toContain('custom 404 page')
  })

  it('should render error cor

 error in the logs for 404 SSG', async () => {
    const gip404Err =
      /`pages\/404` can not have getInitialProps\/getServerSideProps/
    await next.render('/non-existent')
    expect(next.cliOutput).not.toMatch(gip404Err)
  })

  it('should render in

rectly', async () => {
    const text = await next.render('/err')
    if (isNextStart) {
      expect(text).toContain('Internal Server Error')
    } else {
      expect(text).toContain('oops')
    }
  })

  it('should not show an


s from './Component2.module.scss'

export default function Content2() {
  return (

Where does it come from?

        Contrary to popular belief, Lorem Ipsum is not simply random text. It
        has roots in a piece of classical Latin literature from 45 BC, making it
        over 2000 years old. Richard McClintock, a Latin professor at
        Hampden-Sydney College in Virginia, looked u

ctions 1.10.32 and 1.10.33
        of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by
        Cicero, written in 45 BC. This book is a treatise on the theory of
        ethics, very popular during the Renaissance. The first line of Lorem

p one of the more obscure
        Latin words, consectetur, from a Lorem Ipsum passage, and going through
        the cites of the word in classical literature, discovered the
        undoubtable source. Lorem Ipsum comes from se


tent.module.css'
import Content2 from './Component2'

export default function Content() {
  return (

Where does it come from?

        Contrary to popular belief, Lorem Ipsum is not simply random text. It
        has roots in a piece of classical Latin literature from 45 BC, making it
        over 2000 years old. Richard McClintock, a Latin professor at
        Hampden-Sydney College in

psum comes from sections 1.10.32 and 1.10.33
        of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by
        Cicero, written in 45 BC. This book is a treatise on the theory of
        ethics, very popular during the Renaissance. The f

Virginia, looked up one of the more obscure
        Latin words, consectetur, from a Lorem Ipsum passage, and going through
        the cites of the word in classical literature, discovered the
        undoubtable source. Lorem I


OCESS_ENV_KEY',
  'ENV_FILE_KEY',
  'ENV_FILE_EMPTY_FIRST',
  'ENV_FILE_PROCESS_ENV',
  'LOCAL_ENV_FILE_KEY',
  'ENV_FILE_LOCAL_OVERRIDE_TEST',
  'PRODUCTION_ENV_FILE_KEY',
  'LOCAL_PRODUCTION_ENV_FILE_KEY',
  'DEVELOPMENT_ENV_FILE_KEY',
  'LOCAL_DEVELOPMENT_ENV_FILE_KEY',
  'ENV_FILE_DEVELOPMENT_OVERRIDE_TEST',
  'ENV_FILE_DEVELOPMENT_LOCAL_OVERRIDEOVERRIDE_TEST',
  'ENV_FILE_PRODUCTION_OVERRIDEOVERRIDE_TEST',
  'ENV_FILE_PRODUCTION_LOCAL_OVERRIDEOVERRIDE_TEST',
  'TEST_ENV_FILE_KEY',
  'LOCAL_TEST_ENV_FIL

_LOCAL_KEY',
  'NEW_ENV_DEV_KEY',
  'NEXT_PUBLIC_HELLO_WORLD',
]

export async function getStaticProps() {
  const items = {}

  variables.forEach((variable) => {
    if (typeof process.env[variable] !== 'undefined') {
      items[variable] = process.env[v

E_KEY',
  'ENV_FILE_TEST_OVERRIDE_TEST',
  'ENV_FILE_TEST_LOCAL_OVERRIDEOVERRIDE_TEST',
  'ENV_FILE_EXPANDED',
  'ENV_FILE_EXPANDED_CONCAT',
  'ENV_FILE_EXPANDED_ESCAPED',
  'ENV_FILE_KEY_EXCLAMATION',
  'NEW_ENV_KEY',
  'NEW_ENV


_LOCAL_KEY',
  'NEW_ENV_DEV_KEY',
  'NEXT_PUBLIC_HELLO_WORLD',
]

export async function getServerSideProps() {
  const items = {}

  variables.forEach((variable) => {
    if (typeof process.env[variable] !== 'undefined') {
      items[variable] = process.e


mpiled/strip-ansi'
import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'

describe('edge-runtime-streaming-error', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    disableAutoSkewProtection: true,
    // Assertions don't apply to deploy mode (output differs vs. local Next.js server).
    skipDeployment: true,
  })
  if (skipped) return

  it('logs the error correctly', async () => {
    const res = await next.fetch('/api/test')
    expect(await res.te

00)

    await retry(() => {
      expect(stripAnsi(next.cliOutput)).toMatch(
        /The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received type boolean/
      )
    })
    expect(stripAnsi(next.cliOutput)).not.toCon

xt()).toEqual('hello')
    expect(res.status).toBe(2


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

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

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

locale, locales, defaultLocale }) => {
  // ensure getStaticProps isn't called without params
  if (!params || !params.slug) {
    throw new Error(`missing params ${JSON.stringify(params)}`)
  }

  return {
    props: {
      params,
      locale,
      lo

{router.pathname}

{router.asPath}

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

    </>
  )
}

export const getStaticProps = ({ params,


k from 'next/link'
import { useRouter } from 'next/router'

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

{router.asPath}

      <Lin

"to-index">
        to /
      </Link>
      <br />
    </>
  )
}

export const getStaticProps = ({ locale, locales }) => {
  if (locale === 'en' || locale === 'nl') {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      locale,


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

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

  return (
    <>

dynamic page

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

{router.a

fallback-first">
        to /gsp/fallback/first
      </Link>

      <Link href="/gsp/fallback/hello" id="to-fallback-hello">
        to /gsp/fallback/hello
      </Link>

      <Link href="/gsp/no-fallback/first" id="to-no-fallback

sPath}

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

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

      <Link href="/gsp/fallback/first" id="to-