ls'

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

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

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

  it('should not error when visited directly', async () => {

anifest = await next.readJSON('.next/server/pages-manifest.json')
      const page = manifest['/500']
      expect(page.endsWith('.html')).toBe(true)
    })

    it('should add /500 to pages-manifest correctly', async () => {
      const manifest = await n

 const res = await next.fetch('/500')
    expect(res.status).toBe(500)
    expect(await res.text()).toContain('custom 500 page')
  })

  if (isNextStart) {
    it('should output 500.html during build', async () => {
      const m


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

// Turbopack hasn't fully enabled this option yet
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'next-config-warnings - esm-externals-false',
  () => {
    const { next, isNextStart } = nextTestSetup({
      files: __dirname,
      env: {
        NEXT_TELEMETRY_DEBUG: '1',
      },
    })

    it('should warn when using ESM externals: false', async () => {
      await next.fetch('/')

      expect(

nfig.js`
      )
    })

    if (isNextStart) {
      it('should contain esmExternals feature usage in telemetry', async () => {
        const featureUsageEvents = findAllTelemetryEvents(
          next.cliOutput,
          'NEXT_BUILD_FEATURE_USAGE'

next.cliOutput).toContain(
        `The "experimental.esmExternals" option has been modified. experimental.esmExternals is not recommended to be modified as it may disrupt module resolution. It should be removed from your next.co


ml, selector) {
  const $ = cheerio.load(html)
  return $(selector)
}

async function resolveStreamResponse(response, onData) {
  let result = ''
  onData = onData || (() => {})
  await new Promise((resolve) => {
    response.body.on('data', (chunk) => {
      result += chunk.toString()
      onData(chunk.toString(), result)
    })

    response.body.on('end', resolve)
  })
  return result
}

describe('streaming-ssr-edge', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  i

false

        await resolveStreamResponse(response, (_, result) => {
          gotData = result.includes('next_streaming_data')
          if (!gotFallback) {
            gotFallback = result.includes('next_streaming_fallback')
            if (gotFallback)

t('should support streaming for fizz response', async () => {
    async function testStreamingResponse(pathname) {
      await next.fetch(pathname).then(async (response) => {
        let gotFallback = false
        let gotData =


port { nextTestSetup } from 'e2e-utils'

describe('turbopack-loader-config', () => {
  const { next, isTurbopack, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    // we can't set `nextConfig` inline because it contains regexes that fail to serialize, it needs
    // to be set in a separate module (`next.config.ts`)
  })

  if (skipped) {
    return
  }

  if (!isTurbopack) {
    it('should only run the test in turbopack', () => {})
    return
  }

  it('should repla

h their loader-generated versions', async () => {
    const response = JSON.parse(await next.render('/api'))
    expect(response).toEqual({
      foo: 'default return value',
      bar: 'has export substring' + (isNextDev ? ' on dev' : ' on prod'),
    })


ack: {
    rules: {
      // an empty condition should match
      'foo.js': {
        condition: {},
        // use the shorthand syntax
        loaders: ['./webpack-loader-replace-with-stub.cjs'],
      },
      'bar.js': [
        // this condition should not match
        {
          condition: 'foreign',
          loaders: [
            {
              loader: './webpack-loader-replace-with-stub.cjs',
              options: { returnValue: 'foreign' },
            },
          ],
        },
        // t

 options: { returnValue: 'missing export' },
            },
          ],
        },
        // this should match on dev
        {
          condition: {
            any: [
              {
                all: [
                  'development',

his condition should not match
        {
          condition: {
            not: { content: /export/ },
          },
          loaders: [
            {
              loader: './webpack-loader-replace-with-stub.cjs',


retry } from 'next-test-utils'

describe('Custom routes i18n custom error', () => {
  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

  const locales = ['en', 'fr', 'de', 'it']

  it('should localized [slug] routes render correctly', async () => {
    for (const locale of locales) {
      const browser = await next.browser(
        `${locale === 'en' ?

stom-path-1',
      })
    }
  })

  it('handle custom http status maintaining locale props in custom _error page', async () => {
    for (const locale of locales) {
      const browser = await next.browser(
        `${locale === 'en' ? '' : `/${locale}`}/

 '' : `/${locale}`}/my-custom-path-1`
      )

      expect(JSON.parse(await browser.elementByCss('#props').text())).toEqual({
        locale,
        params: {
          slug: 'my-custom-path-1',
        },
        title: 'my-cu


useRouter } from 'next/router'

const SlugPage = (props) => {
  const router = useRouter()

  return router.isFallback ? null : (
    <>

{props.title}

{JSON.stringify(props)}

    </>
  )
}

export const getStaticProps = async ({ locale, params }) => {
  if (params.slug === 'my-custom-gone-path') {
    return {
      notFound: true,
    }
  }
  return {
    props: {
      locale,
      params,
      title: params.slug,
    },
  }
}

export const getStaticPaths =

om-path-1', 'my-custom-path-2']

  return {
    paths: locales.reduce(
      (paths, locale) => [
        ...paths,
        ...mySlugs.map((slug) => ({ locale, params: { slug } })),
      ],
      []
    ),
    fallback: 'blocking',
  }
}

export default S

async ({ locales }) => {
  const mySlugs = ['my-cust


res1 = await next.fetch('/api/proxy-self')
    expect(res1.status).toBe(200)
    expect(await res1.text()).toContain('User')

    const buildId = isNextDev
      ? 'development'
      : await next.readFile('.next/BUILD_ID')

    const res2 = await next.fetch(`/api/proxy-self?buildId=${buildId}`)
    expect(res2.status).toBe(200)
    expect(await res2.text()).toContain('__SSG_MANIFEST')
  })

  it('should respond from /api/auth/[...nextauth] correctly', async () => {
    const res = await next.fetch('/api/au

tus-204', { redirect: 'manual' })
    expect(res.status).toBe(204)
    expect(res.headers.get('content-type')).toBe(null)
    expect(res.headers.get('content-length')).toBe(null)
    expect(res.headers.get('transfer-encoding')).toBe(null)

    const cliOut

th/signin', { redirect: 'manual' })
    expect(res.status).toBe(200)
    expect(await res.json()).toEqual({ from: 'auth' })
  })

  it('should handle 204 status correctly', async () => {
    const res = await next.fetch('/api/sta


it for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function initMiddleware(middleware) {
  return (req, res) =>
    new Promise((resolve, reject) => {
      middleware(req, res, (result) => {
        if (result instanceof Error) {
          return reject(result)
        }
        return resolve(result)
      })
    })
}

// Initialize the cors middleware
const cors = initMiddleware(
  // You can read more about the available options here: https://

rs({
    // Only allow requests with GET, POST and OPTIONS
    methods: ['GET', 'POST', 'OPTIONS'],
  })
)

export default async function handler(req, res) {
  // Run cors
  await cors(req, res)

  // Rest of the API logic
  res.json({ message: 'Hello Ever

github.com/expressjs/cors#configuration-options
  Co


 { nextTestSetup } from 'e2e-utils'

describe('invalid-static-asset-404-app-asset-prefix', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      assetPrefix: '/assets',
    },
  })

  it('should return correct output with status 200 on valid asset path', async () => {
    const buildManifestPath = `/assets/_next/static/${next.buildId}/_buildManifest.js${next.getDeploymentIdQuery()}`

    const res = await next.fetch(buildManifestPath)
    expect(res.status).toBe(200)
    c

ct(res.status).toBe(404)
    const text = await res.text()
    expect(text).toContain('Custom Not Found')
  })

  it('should return 404 with plain text when fetching invalid asset path', async () => {
    const res = await next.fetch('/assets/_next/static/

onst text = await res.text()
    expect(text).toContain('__BUILD_MANIFEST')
  })

  it('should return custom 404 page when fetching invalid non-asset path', async () => {
    const res = await next.fetch('/invalid-path')
    expe


ort { nextTestSetup } from 'e2e-utils'

describe('invalid-static-asset-404-app-base-path', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      basePath: '/base',
    },
  })

  it('should return correct output with status 200 on valid asset path', async () => {
    const buildManifestPath = `/base/_next/static/${next.buildId}/_buildManifest.js${next.getDeploymentIdQuery()}`

    const res = await next.fetch(buildManifestPath)
    expect(res.status).toBe(200)
    const te

(res.status).toBe(404)
    const text = await res.text()
    expect(text).toContain('Custom Not Found')
  })

  it('should return 404 with plain text when fetching invalid asset path', async () => {
    const res = await next.fetch('/base/_next/static/inva

xt = await res.text()
    expect(text).toContain('__BUILD_MANIFEST')
  })

  it('should return custom 404 page when fetching invalid non-asset path', async () => {
    const res = await next.fetch('/base/invalid-path')
    expect


fetchViaHTTP } from 'next-test-utils'

describe('edge api can use async local storage', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  const cases = [
    {
      title: 'a single instance',
      route: '/api/single',
      expectResponse: (response: any, id: string) =>
        expect(response).toMatchObject({ status: 200, json: { id } }),
    },
    {
      title: 'multiple instances',
      route: '/api/multiple',
      expectResponse: (response: any, id: string) =>
        expe

  const ids = Array.from({ length: 100 }, (_, i) => `req-${i}`)

      const responses = await Promise.all(
        ids.map((id) =>
          fetchViaHTTP(next.url, route, {}, { headers: { 'req-id': id } }).then(
            (response) =>
              res

ct(response).toMatchObject({
          status: 200,
          json: { id: id, nestedId: `nested-${id}` },
        }),
    },
  ]

  it.each(cases)(
    'can use $title per request',
    async ({ route, expectResponse }) => {


 (e. g. 'eval', 'new Function') not allowed in Edge Runtime`
const DYNAMIC_CODE_ERROR = `Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime`
const WASM_COMPILE_ERROR = `Dynamic WASM code generation (e. g. 'WebAssembly.compile') not allowed in Edge Runtime`
const WASM_INSTANTIATE_ERROR = `Dynamic WASM code generation ('WebAssembly.instantiate' with a buffer parameter) not allowed in Edge Runtime`

jest.setTimeout(1000 * 60 * 2)

type NextFetchResponse =

nextTestSetup({
    files: __dirname,
  })

  it('does not issue dynamic code evaluation warnings', async () => {
    const outputIndex = next.cliOutput.length
    const html = await next.render('/')
    expect(html).toMatch(/>.*?100.*?and.*?100.*?<\//)

Awaited<
  ReturnType<ReturnType<typeof nextTestSetup>['next']['fetch']>
>

describe('Page using eval in development mode', () => {
  if (!isNextDev) {
    it('only runs in dev mode', () => {})
    return
  }

  const { next } =


quare.wasm?module'

export async function usingWebAssemblyCompile(x) {
  const module = await WebAssembly.compile(SQUARE_WASM_BUFFER)
  const instance = await WebAssembly.instantiate(module, {})
  return { value: instance.exports.square(x) }
}

export asyn


  usingWebAssemblyInstantiate,
  usingWebAssemblyInstantiateWithBuffer,
} from '../../lib/wasm'

export default async function handler(request) {
  const useCase = request.nextUrl.searchParams.get('case')

  if (useCase === 'using-eval') {
    return Response.json(await usingEval())
  }

  if (useCase === 'not-using-eval') {
    return Response.json(await notUsingEval())
  }

  if (useCase === 'using-webassembly-compile') {
    return Response.json(await usingWebAssemblyCompile(9))
  }

  if (useCase === 'u

.json(await usingWebAssemblyInstantiate(9))
  }

  if (useCase === 'using-webassembly-instantiate-with-buffer') {
    return Response.json(await usingWebAssemblyInstantiateWithBuffer(9))
  }

  return Response.json({ ok: true })
}

export const config = {

sing-webassembly-instantiate') {
    return Response


 - partytown-missing', () => {
  const { next, isNextDev } = nextTestSetup({
    files: join(__dirname, 'partytown-missing'),
    skipStart: true,
    // Vercel deployment fails to build/deploy this fixture in CI; skip in deploy mode.
    skipDeployment: true,
  })

  it('Error message is shown if Partytown is not installed locally', async () => {
    if (isNextDev) return

    const { cliOutput } = await next.build()

    expect(cliOutput.replace(/[\n\r]/g, '')).toMatch(
      /It looks like you're trying

he required package\(s\) installed.Please install Partytown by running:.*?(npm|pnpm|yarn) (install|add) (--save-dev|--dev) @builder\.io\/partytownIf you are not trying to use Partytown, please disable the experimental "nextScriptWorkers" flag in next\.conf

to use Partytown with next\/script but do not have t


mport * as React from 'react'
import { Main, NextScript, Head, Html } from 'next/document'
import Script from 'next/script'

export default function Document() {
  return (
    <Html>
      <Head>
        <link
          rel="stylesheet"
          href="https://fonts.googleapis.com/css?family=Voces"
        />
        <Script
          id="scriptBeforeInteractive"
          src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
          strategy="beforeIntera

  ></Script>
      </Head>
      <body>
        <Main />
        <NextScript />
        <Script
          src="https://www.google-analytics.com/analytics.js?a=scriptBeforeInteractive"
          strategy="beforeInteractive"
        ></Script>
        <div i

ctive"
        ></Script>
        <Script
          id="inline-before"
          strategy="beforeInteractive"
          dangerouslySetInnerHTML={{
            __html: `console.log('inline beforeInteractive')`,
          }}


/* global _ */
import Script from 'next/script'
import Link from 'next/link'

const url =
  'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js'

const Page = () => {
  return (

initial

      <Link href="/page9">Page 9</Link>

   ></Script>
      <Script
        src={url}
        id="script3"
        onLoad={() => {
          document.getElementById('onload-div-1').textContent += _.repeat(
            'c',
            3
          )
        }}
      ></Script>
    </div>
  )
}

e

}}
      ></Script>
      <Script
        src={url}
        id="script2"
        onLoad={() => {
          document.getElementById('onload-div-1').textContent += _.repeat(
            'b',
            3
          )
        }}


llow manual href/as on index page', async () => {
    const browser = await next.browser('/')

    expect(await browser.elementByCss('#index').text()).toBe('index page')
    expect(await browser.hasElementByCssSelector('#modal')).toBeFalsy()
    await browser.eval('window.beforeNav = 1')

    await browser.elementByCss('#to-modal').click()

    expect(await browser.elementByCss('#index').text()).toBe('index page')
    expect(await browser.hasElementByCssSelector('#modal')).toBeTruthy()
    expect(await brow

lementByCss('#preview')

    expect(await browser.elementByCss('#preview').text()).toBe('preview page')
    expect(await browser.eval('window.beforeNav')).toBe(1)
    expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
      slug: '12

ser.eval('window.beforeNav')).toBe(1)
    expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
      imageId: '123',
    })

    await browser
      .elementByCss('#to-preview')
      .click()
      .waitForE


 'react'
import FourDirect from '../components/four'

const One = dynamic(() => import('../components/one'))
const Two = dynamic(() => import('../components/two'))
const Three = dynamic(() => import('../components/three'))
const Four = dynamic(() => import('../components/four'))

if (typeof window !== 'undefined') {
  window.caughtErrors = ''
  const origError = console.error

  console.error = function (...args) {
    window.caughtErrors += args.join(' ')
    origError(...args)
  }
}

export default () =>

the-server-value')
  useEffect(() => {
    setFirstRender(document.getElementById('foo').innerHTML)
  }, [])

  return (
    <>
      <div id="foo">
        Index
        <One />
        <Two />
        <Three />
        <Four />
        <FourDirect />

{
  const [firstRender, setFirstRender] = useState('


avigateProps {
  children: React.ReactNode
  rootPath: string
}

export default function OnNavigate({ children, rootPath }: OnNavigateProps) {
  const [isClicked, setIsClicked] = useState(false)
  const [isNavigated, setIsNavigated] = useState(false)
  const [isLocked, setIsLocked] = useState(false)

  return (

isClicked: {isClicked ? 'true' : 'false'}

isNavigated: {isNavigated ? 'true'

ton>

        <div>
          <Link
            href={rootPath}
            id="link-to-main"
            onClick={() => setIsClicked(true)}
            onNavigate={(e: any) => {
              if (isLocked) {
                e.preventDefault()

: 'false'}

isLocked: {isLocked ? 'true' : 'false'}

        <button id="toggle-lock" onClick={() => setIsLocked(!isLocked)}>
          {isLocked ? 'Unlock' : 'Lock'}
        </but


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

describe('Edge API endpoints can receive body', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/api/edge.js': new FileRef(
        path.resolve(__dirname, './app/pages/api/edge.js')
      ),
      'pages/api/index.js': new FileRef(
        path.resolve(__dirname, './app/pages/api/index.js')
      ),
    },
    dependencies: {},
  })

  it('reads the body as text', asyn

).toBe('got: hello, world.')
  })

  it('reads the body from index', async () => {
    const res = await fetchViaHTTP(
      next.url,
      '/api',
      {},
      {
        body: 'hello, world.',
        method: 'POST',
      }
    )

    expect(res.stat

c () => {
    const res = await fetchViaHTTP(
      next.url,
      '/api/edge',
      {},
      {
        body: 'hello, world.',
        method: 'POST',
      }
    )

    expect(res.status).toBe(200)
    expect(await res.text()


ow pending state for the last link clicked when clicking multiple links in a row', async () => {
    const browser = await next.browser('/')

    // Click post 1 link
    await browser.elementById('post-1-link').click()

    // Quickly click post 2 link
    await browser.elementById('post-2-link').click()

    // The pending state should be shown for post 2 link
    expect(await browser.elementById('post-2-loading').text()).toBe('(Loading)')

    // Post 1 should not show loading
    const post1Loading = aw

Css('[data-testid="post-2-page"]')
  })

  it('should remove pending state after shallow routing', async () => {
    const browser = await next.browser('/')

    // Click post 1 link
    await browser.elementById('post-1-link').click()

    // Verify pendi

ait browser.elementsByCss('#post-1-loading')
    expect(post1Loading.length).toBe(0)

    // Wait for navigation to complete and verify we end up on post 2
    await browser.waitForIdleNetwork()
    await browser.waitForElementBy


xt/link'
import { navigateByServerAction } from './server-action'
import { useRouter } from 'next/navigation'

export default function NavBar() {
  const postIds = Array.from({ length: 5 }, (_, i) => i + 1)
  const router = useRouter()

  return (

          <Link
            prefetch={false}
            href="/"
            id="home-link"
            data-testid="home-link"
          >

  >
            Navigate by server action to home
          </button>
        </li>
        {postIds.map((id) => (
          <li key={id}>
            <Link
              prefetch={false}
              href={`/post/${id}`}
              id={`post-${id}-lin

    Home <LoadingIndicator id="home" />
          </Link>
          <button
            id="server-action-home-btn"
            data-testid="server-action-home-btn"
            onClick={() => navigateByServerAction(`/`)}


tTestSetup } from 'e2e-utils'

describe('Route index handling', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    // Pages-router `/index` route resolution differs in Vercel's deploy
    // infrastructure; these assertions are local-only.
    skipDeployment: true,
  })

  it('should handle / correctly', async () => {
    const res = await next.fetch('/')
    expect(res.status).toBe(404)
    expect(await res.text()).toContain('page could not be found')
  })

  it('should handle /index corr

st res = await next.fetch('/index/index')
    expect(res.status).toBe(404)
    expect(await res.text()).toContain('page could not be found')
  })

  it('should handle /index/?bar%60%3C%25%22%27%7B%24%2A%25%5C correctly', async () => {
    const res = await

ectly', async () => {
    const res = await next.fetch('/index')
    expect(res.status).toBe(200)
    expect(await res.text()).toContain('hello from index')
  })

  it('should handle /index/index correctly', async () => {
    con


 = nextTestSetup({
    files: __dirname,
    // Pages-router `/index` route resolution differs in Vercel's deploy
    // infrastructure; these assertions are local-only.
    skipDeployment: true,
  })

  it('should handle / correctly', async () => {
    const res = await next.fetch('/')
    expect(res.status).toBe(200)
    expect(await res.text()).toContain('hello from index')
  })

  it('should handle /index correctly', async () => {
    const res = await next.fetch('/index')
    expect(res.status).toBe(40

ait res.text()).toContain('page could not be found')
  })

  it('should handle /nested-index correctly', async () => {
    const res = await next.fetch('/nested-index')
    expect(res.status).toBe(404)
    expect(await res.text()).toContain('page could not

4)
    expect(await res.text()).toContain('page could not be found')
  })

  it('should handle /index/index correctly', async () => {
    const res = await next.fetch('/index/index')
    expect(res.status).toBe(404)
    expect(aw


from 'e2e-utils'

const jsContent = `export const nope = 'nope'

throw new Error('please dont execute me')
`

;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
  'turbopack-import-with-type',
  () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      skipDeployment: true,
    })

    if (skipped) {
      return
    }

    // Testing this together on one route ensures we also avoid weird duplicate module ident things
    it('supports import with type: text, type: bytes,

        },
        jsAsText: {
          typeofString: true,
          content: jsContent,
        },
        bytes: {
          instanceofUint8Array: true,
          length: 18,
          content: 'this is some data\n',
        },
        jsAsBytes: {

and type: json', async () => {
      const response = JSON.parse(await next.render('/api'))
      expect(response).toEqual({
        text: {
          typeofString: true,
          length: 12,
          content: 'hello world\n',


th'
import { nextTestSetup } from 'e2e-utils'

describe('Optimized loading', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, '../'),
  })

  function runTests(url) {
    describe('page ' + url, () => {
      it(`should render the page ${url}`, async () => {
        const html = await next.render(url)
        expect(html).toMatch(/Hello World/)
      })

      it('should not have JS preload links', async () => {
        const $ = await next.render$(url)
        expect($('link[rel=preloa

 scripts with defer in head', async () => {
        const $ = await next.render$(url)
        expect($('script[async]').length).toBe(0)
        expect($('head script[defer]').length).toBeGreaterThan(0)
      })
    })
  }

  runTests('/')
  runTests('/page

d]').length).toBe(0)
      })

      it('should load


from 'e2e-utils'
import { listClientChunks, retry } from 'next-test-utils'
import fs from 'fs'
import path from 'path'

describe('swc-auto-polyfill', () => {
  const { next, isNextDev, isNextDeploy } = nextTestSetup({
    files: __dirname,
    dependencies: {
      'core-js': '3.38.1',
    },
  })

  it('should render the page correctly with swcEnvOptions enabled', async () => {
    const browser = await next.browser('/')
    await retry(async () => {
      const text = await browser.elementByCss('#result')

ath.join(next.testDir, next.distDir))
      ).filter((f) => f.endsWith('.js'))

      // Find a chunk that contains BOTH the user code (a-b-c / a_b_c) AND
      // core-js polyfill artifacts. This proves SWC's usage-mode polyfill
      // injection is work

.text()
      expect(text).toBe('a_b_c')
    })
  })

  if (!isNextDev && !isNextDeploy) {
    it('should include core-js polyfill in a chunk with user code', async () => {
      const jsFiles = (
        await listClientChunks(p


from 'e2e-utils'

describe('edge-runtime uses edge-light import specifier for packages', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    packageJson: {
      scripts: {
        build: 'next build',
        dev: 'next dev',
        start: 'next start',
      },
    },
    installCommand: 'pnpm i',
    startCommand: (global as any).isNextDev ? 'pnpm dev' : 'pnpm start',
    buildCommand: 'pnpm build',
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  // In case y

t is only supported in `exports` and `imports` but webpack also adds the top level `edge-light` key incorrectly.
      edgeLightPackage: process.env.IS_TURBOPACK_TEST ? 'import' : 'edge-light',
      edgeLightPackageExports: 'edge-light',
    })
  })

  it

ou need to test the response object
  it('pages/api endpoints import the correct module', async () => {
    const res = await next.fetch('/api/edge')
    const html = await res.json()
    expect(html).toEqual({
      // edge-ligh


  // TODO: We will refactor the next/script to be strict mode resilient
  // Don't skip the test case for development mode (strict mode) once refactoring is finished
  it('priority afterInteractive', async () => {
    const browser = await next.browser('/')

    async function test(scriptID: string) {
      await retry(async () => {
        const script = await browser.elementByCss(`script#${scriptID}`)
        const dataAttr = await script.getAttribute('data-nscript')
        const endScripts = await brows

active script in page
    await test('scriptAfterInteractive')
    // afterInteractive script in _document
    await test('documentAfterInteractive')
  })

  it('priority lazyOnload', async () => {
    const browser = await next.browser('/page3')

    awai

er.elementsByCss(
          `#__NEXT_DATA__ ~ script#${scriptID}`
        )

        expect(script).toBeDefined()
        expect(dataAttr).toBeDefined()

        expect(endScripts.length).toBe(1)
      })
    }

    // afterInter


from 'e2e-utils'
import { createServer, Server } from 'http'

describe('node-fetch-keep-alive', () => {
  let mockServer: Server

  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    // Vercel deployment fails to build/deploy this fixture in CI; skip in deploy mode.
    skipDeployment: true,
  })
  if (skipped) return

  beforeAll(async () => {
    mockServer = createServer((req, res) => {
      const { connection } = req.headers
      res.end(JSON.stringify({ connectio

const res = await next.fetch('/api/json')
    const obj = await res.json()
    expect(obj).toEqual({ connection: 'keep-alive' })
  })

  it('should send keep-alive for getStaticProps', async () => {
    const browser = await next.browser('/ssg')
    const

n }))
    })
    await new Promise<void>((resolve) => mockServer.listen(44001, resolve))
    await next.start()
  })

  afterAll(() => {
    mockServer?.close()
  })

  it('should send keep-alive for json API', async () => {


/app-router' },
    { name: 'Pages Router', path: '/pages-router' },
  ]

  routers.forEach(({ name, path }) => {
    describe(name, () => {
      it('should trigger onClick but not onNavigate when using modifier key', async () => {
        const browser = await next.browser(path)

        // Check initial state
        expect(await browser.elementById('is-clicked').text()).toBe(
          'isClicked: false'
        )
        expect(await browser.elementById('is-navigated').text()).toBe(
          'isNaviga

down the modifier key
        await browser.keydown(modifierKey)

        // Click the link while the modifier key is pressed
        await browser.elementById('link-to-subpage').click()

        // Release the modifier key
        await browser.keyup(modi

ted: false'
        )

        // Click with modifier key based on OS to open in new window
        const platform = process.platform
        const modifierKey = platform === 'darwin' ? 'Meta' : 'Control'

        // First press


import { nextTestSetup } from 'e2e-utils'

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

  it('back-button should go back to rewritten path successfully', async () => {
    const browser

click()
      .waitForElementByCss('#index')

    await browser.back().waitForElementByCss('#another')

    expect(await browser.waitForElementByCss('#another').text()).toBe(
      'another page'
    )

    expect(await browser.eval('window.beforeNav')).to

 = await next.browser('/rewrite-me/path')

    expect(await browser.elementByCss('#another').text()).toBe('another page')

    await browser.eval('window.beforeNav = 1')

    await browser
      .elementByCss('#to-index')
      .


import * as path from 'path'
import { nextTestSetup, type NextInstance } from 'e2e-utils'
import { File } from 'next-test-utils'
import * as JSON5 from 'json5'

function runTests(next: NextInstance) {
  describe('default behavior', () => {
    it('should alias components', async () => {
      const $ = await next.render$('/basic-alias')
      expect($('body').text()).toMatch(/World/)
    })

    it('should resolve the first item in the array first', async () => {
      const $ = await next.render$('/resolve

).toMatch(/Hello from only b/)
    })

    it('should resolve a single matching alias', async () => {
      const $ = await next.render$('/single-alias')
      expect($('body').text()).toMatch(/Hello/)
    })

    it('should not resolve to .d.ts files', as

-order')
      expect($('body').text()).toMatch(/Hello from a/)
    })

    it('should resolve the second item in as a fallback', async () => {
      const $ = await next.render$('/resolve-fallback')
      expect($('body').text()


o'
import { nextTestSetup, isNextDev } from 'e2e-utils'
import { findPort } from 'next-test-utils'

describe('Fetch polyfill', () => {
  let apiServerPort: number
  let apiServer: http.Server

  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    dependencies: {
      react: '19.3.0-canary-fef12a01-20260413',
      'react-dom': '19.3.0-canary-fef12a01-20260413',
    },
    // Vercel deployment fails to build/deploy this fixture in CI; skip in deploy mode.
    skipDeploym

{ usernames: ['a', 'b'] }))
      }
      if (req.url === '/usernames/a') {
        return res.end(JSON.stringify({ from: 'a' }))
      }
      if (req.url === '/usernames/b') {
        return res.end(JSON.stringify({ from: 'b' }))
      }
      res.end(JS

ent: true,
  })
  if (skipped) return

  beforeAll(async () => {
    apiServerPort = await findPort()

    apiServer = http.createServer((req, res) => {
      if (req.url === '/usernames') {
        return res.end(JSON.stringify(


tResponse } from 'next/server'
import { notUsingEval, usingEval } from './lib/utils'
import {
  usingWebAssemblyCompile,
  usingWebAssemblyInstantiate,
  usingWebAssemblyInstantiateWithBuffer,
} from './lib/wasm'

export async function middleware(request) {
  if (request.nextUrl.pathname === '/using-eval') {
    return new Response(null, {
      headers: { data: JSON.stringify(await usingEval()) },
    })
  }

  if (request.nextUrl.pathname === '/not-using-eval') {
    return new Response(null, {
      head

le(9)) },
    })
  }

  if (request.nextUrl.pathname === '/using-webassembly-instantiate') {
    return new Response(null, {
      headers: { data: JSON.stringify(await usingWebAssemblyInstantiate(9)) },
    })
  }

  if (
    request.nextUrl.pathname ===

ers: { data: JSON.stringify(await notUsingEval()) },
    })
  }

  if (request.nextUrl.pathname === '/using-webassembly-compile') {
    return new Response(null, {
      headers: { data: JSON.stringify(await usingWebAssemblyCompi


() => {
  return (
    <div class="container">
      <Script id="inline-script">
        {`const newDiv = document.createElement('div')
          newDiv.id = 'onload-div'
          document.querySelector('body').appendChild(newDiv)
        `}
      </Script>
      <Script
        id="scriptLazyOnload"
        src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptLazyOnload"
        strategy="lazyOnload"
        stylesheets={[
          'https://cdn.jsdelivr.net/npm/bootstrap@5.

3.0/dist/css/bootstrap.min.css',
        ]}
      ><


d>((r) => {
      resolveReady = () => {
        if (!ready) {
          ready = true
          r()
        }
      }
    })

    const exit = next
      .runCommand(args, {
        env: opts.env,
        cwd: opts.cwd,
        onStdout: (msg) => {
          opts.onStdout?.(msg)
          if (readyPattern.test(stripAnsi(msg))) resolveReady()
        },
        onStderr: (msg) => {
          opts.onStderr?.(msg)
          if (readyPattern.test(stripAnsi(msg))) resolveReady()
        },
        instance: (p)

 let stdout = ''
    let stderr = ''

    let app = http.createServer((_, res) => {
      res.writeHead(200, { 'Content-Type': 'text/plain' })
      res.end('OK')
    })

    await new Promise<void>((resolve, reject) => {
      app.on('error', reject)

=> {
          child = p
        },
      })
      .finally(() => {
        resolveReady()
      })

    await readyPromise
    return { child, exit }
  }

  const runAndCaptureOutput = async ({ port }: { port: number }) => {


rts swcPlugins', () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      skipDeployment: true,
      dependencies: {
        '@swc/plugin-react-remove-properties': '11.1.0',
      },
    })
    if (skipped) return

    it('basic case', async () => {
      const html = await next.render('/')
      expect(html).toContain('Hello World')
      expect(html).not.toContain('data-custom-attribute')
    })
  })
  ;(isNextDev ? describe : describe.skip)('incompatible plugin version', () =>

rn

    it('shows a redbox in dev', async () => {
      const browser = await next.browser('/')

      if (isTurbopack) {
        await expect(browser).toDisplayRedbox(`
         {
           "description": "Failed to execute SWC plugin",
           "envir

 {
    const { next, skipped, isTurbopack } = nextTestSetup({
      files: __dirname,
      skipDeployment: true,
      dependencies: {
        '@swc/plugin-react-remove-properties': '7.0.2',
      },
    })
    if (skipped) retu


fetchViaHTTP, renderViaHTTP } from 'next-test-utils'
import path from 'path'
import fs from 'fs-extra'

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

describe('i18n-ignore-rewrite-source-locale', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/api/hello.js': `
      export default function handler(req, res) {
        res.send('hello from api')
      }`,
      'public/file.txt': 'hello from file.txt',
    },
    dependencies: {},
    nextConfig: {
      i18n: {
        locales: ['en', 'sv',

     locale: false,
            },
            {
              source: '/:locale/rewrite-api/:path*',
              destination: '/api/:path*',
              locale: false,
            },
          ],
          afterFiles: [],
          fallback: [],

 'nl'],
        defaultLocale: 'en',
      },
      async rewrites() {
        return {
          beforeFiles: [
            {
              source: '/:locale/rewrite-files/:path*',
              destination: '/:path*',


           <Html>
              <Head>
                <Script
                  src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"
                  strategy="beforeInteractive"
                ></Script>
              </Head>
              <body>
                <Main />
                <NextScript />
              </body>
            </Html>
          )
        }
      `,
      'pages/index.js': `
        export default function Home() {
          return (
            <>

script = await browser.eval(
        `document.querySelector('script[data-nscript="beforeInteractive"]')`
      )
      expect(script).not.toBeNull()
    } finally {
      if (browser) await browser.close()
    }
  })
})

describe('beforeInteractive in doc

Home page

            </>
          )
        }
      `,
    },
  })

  it('Script is injected server-side', async () => {
    let browser: Playwright

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

      const


, () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      sass: 'latest',
    },
  })

  it('should load a Pages Router page correctly', async () => {
    const browser = await next.browser('/')

    expect(
      await browser
        .elementByCss('#__next div:nth-child(2)')
        .getComputedCss('background-color')
    ).toContain('221, 221, 221')

    expect(await browser.eval('document.documentElement.innerHTML')).toContain(
      'Where does it come from?'
    )

async () => {
    const browser = await next.browser('/test-app')

    expect(
      await browser
        .elementByCss('body div:nth-child(3)')
        .getComputedCss('background-color')
    ).toContain('221, 221, 221')

    expect(await browser.eval('d

})

  it('should load a App Router page correctly',


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


h'
import { FileRef, nextTestSetup } from 'e2e-utils'

describe('i18-preferred-locale-redirect', () => {
  const { next } = nextTestSetup({
    files: new FileRef(join(__dirname, './app/')),
  })

  it('should request a path prefixed with my preferred detected locale when accessing index', async () => {
    const browser = await next.browser('/new', {
      locale: 'id',
    })

    let requestedPreferredLocalePathCount = 0
    browser.on('request', (request) => {
      if (new URL(request.url(), 'http://n'

IRECTS/)

    await browser.waitForElementByCss('#index')

    expect(await browser.elementByCss('#index').text()).toBe('Index')
    expect(await browser.elementByCss('#current-locale').text()).toBe('id')

    expect(requestedPreferredLocalePathCount).toBe

).pathname === '/id') {
        requestedPreferredLocalePathCount++
      }
    })

    const goToIndex = async () => {
      await browser.get(next.url)
    }

    await expect(goToIndex()).resolves.not.toThrow(/ERR_TOO_MANY_RED


t */

import { join } from 'path'
import { nextTestSetup, FileRef } from 'e2e-utils'

describe('Custom TypeScript Config', () => {
  const { next, skipped } = nextTestSetup({
    files: new FileRef(join(__dirname, '..')),
    dependencies: {
      typescript: '5.4.4',
    },
  })

  if (skipped) {
    return
  }

  it('app router: allows a user-specific tsconfig via the next config', async () => {
    const html = await next.render('/')
    expect(html).toContain('bar123')
  })

  it('pages router: allows a

() => {
    const html = await next.render('/page')
    expect(html).toContain('bar123')
  })

  it('middleware: allows a user-specific tsconfig via the next config', async () => {
    const html = await next.render('/middleware')
    expect(html).toContai


check, waitFor } from 'next-test-utils'
import path from 'path'

describe('multi-zone', () => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: path.join(__dirname, 'app'),
    skipDeployment: true,
    buildCommand: 'pnpm build',
    startCommand: (global as any).isNextDev ? 'pnpm dev' : 'pnpm start',
    serverReadyPattern: /Next mode: (production|development)/,
    packageJson: {
      scripts: {
        dev: 'node server.js',
        build: 'next build apps/host && next build apps/gues

thname: '/', content: ['hello from host app'] },
    { pathname: '/guest', content: ['hello from guest app'] },
    {
      pathname: '/blog/post-1',
      content: ['hello from host app /blog/[slug]'],
    },
    {
      pathname: '/guest/blog/post-1',

t',
        start: 'NODE_ENV=production node server.js',
        'post-build': 'echo done',
      },
    },
    dependencies: require('./app/package.json').dependencies,
  })

  if (skipped) {
    return
  }

  it.each([
    { pa


 require('next')
const path = require('path')
const { parse } = require('url')
const http = require('http')

;(async () => {
  const requestHandlers = new Map()
  const dev = process.env.NODE_ENV !== 'production'

  for (const appName of ['host', 'guest']) {
    const appDir = path.join(__dirname, 'apps', appName)
    const nextApp = next({
      dir: appDir,
      dev,
    })

    await nextApp.prepare()
    const handler = nextApp.getRequestHandler()
    requestHandlers.set(appName, handler)
  }

  const

s.end('not found')
    }

    try {
      await handler(req, res, parse(req.url, true))
    } catch (err) {
      console.error(err)
      res.statusCode = 500
      res.end('internal error')
    }
  })
  const parsedPort = Number(process.env.PORT)
  const

server = http.createServer(async (req, res) => {
    const appName = req.url.startsWith('/guest') ? 'guest' : 'host'
    const handler = requestHandlers.get(appName)

    if (!handler) {
      res.statusCode = 404
      return re


th'

const dir = path.join(path.dirname(new URL(import.meta.url).pathname), '../..')
const logPath = path.join(dir, 'output-log.json')

export async function POST(req) {
  let payloadString = ''
  const decoder = new TextDecoder()
  const reader = req.clone().body.getReader()
  while (true) {
    const { done, value } = await reader.read()
    if (done) {
      break
    }

    payloadString += decoder.decode(value)
  }

  const payload = JSON.parse(payloadString)

  const json = fs.existsSync(logPath)

  : {}

  if (!json[payload.message]) {
    json[payload.message] = {
      payload,
      count: 1,
    }
  } else {
    json[payload.message].count++
  }

  await fsp.writeFile(logPath, JSON.stringify(json, null, 2), 'utf8')

  console.log(`[instrumentat

? JSON.parse(await fsp.readFile(logPath, 'utf8'))


waitFor } from 'next-test-utils'

describe('@next/third-parties basic usage', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      '@next/third-parties': 'canary',
    },
  })

  it('renders YoutubeEmbed', async () => {
    const $ = await next.render$('/youtube-embed')

    const baseContainer = $('[data-ntpc="YouTubeEmbed"]')
    const youtubeContainer = $('lite-youtube')
    expect(baseContainer.length).toBe(1)
    expect(youtubeContainer.length).toBe(1)
  })

  it('

bed/v1/place?key=XYZ"]'
    )
    expect(baseContainer.length).toBe(1)
    expect(mapContainer.length).toBe(1)
  })

  it('renders GTM', async () => {
    const browser = await next.browser('/gtm')

    await browser.waitForElementByCss('script#_next-gtm')

renders GoogleMapsEmbed', async () => {
    const $ = await next.render$('/google-maps-embed')

    const baseContainer = $('[data-ntpc="GoogleMapsEmbed"]')
    const mapContainer = $(
      '[src^="https://www.google.com/maps/em


sNextDev, isNextStart } from 'e2e-utils'

describe('CSS Module client-side navigation', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    // Calls `next.build()` and uses an in-test proxy in front of the Next
    // server; both rely on the local-process model and are not applicable to
    // deploy mode.
    skipDeployment: true,
  })
  if (skipped) return

  let proxyServer: http.Server
  let proxyPort: number
  let stallCss = false

  beforeAll(async () =>

 proxyServer = http.createServer(async (req, res) => {
        if (
          stallCss &&
          req.url &&
          new URL(req.url, next.url).pathname.endsWith('.css')
        ) {
          console.log('stalling request for', req.url)
          await

 {
    if (!isNextDev) {
      await next.build()
    }
    await next.start()

    if (!isNextDev) {
      proxyPort = await findPort()

      const proxy = httpProxy.createProxyServer({
        target: next.url,
      })


rip-ansi'
import { nextTestSetup } from 'e2e-utils'
import { check } from 'next-test-utils'

describe('next.config.js schema validating - defaultConfig', () => {
  const { next, skipped } = nextTestSetup({
    files: {
      'pages/index.js': `
    export default function Page() {
      return
hello world

    }
    `,
      'next.config.js': `
    module.exports = (phase, { defaultConfig }) => {
      return defaultConfig
    }
    `,
    },
    skipDeployment: true,
  })

  if (skipped) {
    return

validating - invalid config', () => {
  const { next, isNextStart, skipped } = nextTestSetup({
    files: {
      'pages/index.js': `
    export default function Page() {
      return
hello world

    }
    `,
      'next.config.js': `
    module.exp

  }

  it('should validate against defaultConfig', async () => {
    const output = stripAnsi(next.cliOutput)

    expect(output).not.toContain('Invalid next.config.js options detected')
  })
})

describe('next.config.js schema


tTestSetup } from 'e2e-utils'

describe('twoslash', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      twoslash: '0.3.4',
      'twoslash-protocol': '0.3.4',
      typescript: '5.9.2',
    },
  })

  it.each(['default', 'esnext'])(
    'should annotate twoslash types %s',
    async (mode) => {
      const { code, nodes, error } = JSON.parse(await next.render(`/?${mode}`))
      expect({ code, nodes, error }).toMatchInlineSnapshot(`
     {
       "code": "type X = Prom

  "text": "type X = Promise<number>",
           "type": "hover",
         },
         {
           "character": 9,
           "docs": "Represents the completion of an asynchronous operation",
           "length": 7,
           "line": 0,
           "start

ise<number>;
     'hello'.toUpperCase()",
       "error": undefined,
       "nodes": [
         {
           "character": 5,
           "length": 1,
           "line": 0,
           "start": 5,
           "target": "X",


om 'path'
import {
  findPort,
  initNextServerScript,
  killApp,
  fetchViaHTTP,
} from 'next-test-utils'

if (!(globalThis as any).isNextStart) {
  it('should skip for non-next start', () => {})
} else {
  describe('output: standalone with twoslash', () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      dependencies: {
        twoslash: '0.3.4',
        'twoslash-protocol': '0.3.4',
        typescript: '5.9.2',
      },
      skipStart: true,
    })

    if (skipped) {

tput', 'output')
      )
      await next.build()

      tmpFolder = path.join(os.tmpdir(), 'next-standalone-' + Date.now())
      await fs.mkdirp(tmpFolder)
      const distFolder = path.join(tmpFolder, 'test')
      await fs.move(path.join(next.testDir,

return
    }

    let server: any
    let appPort: number
    let tmpFolder: string

    beforeAll(async () => {
      await next.patchFile(
        'next.config.js',
        (await next.readFile('next.config.js')).replace('// ou


('Dynamic Route Interpolation', () => {
  const { next, isNextStart } = nextTestSetup({
    files: __dirname,
  })

  it('should work', async () => {
    const $ = await next.render$('/blog/a')
    expect($('#slug').text()).toBe('a')
  })

  it('should work with parameter itself', async () => {
    const $ = await next.render$('/blog/[slug]')
    expect($('#slug').text()).toBe('[slug]')
  })

  it('should work with brackets', async () => {
    const $ = await next.render$('/blog/[abc]')
    expect($('#slug'

kets in API routes', async () => {
    const text = await next.render('/api/dynamic/[abc]')
    expect(text).toBe('slug: [abc]')
  })

  it('should bust data cache', async () => {
    const browser = await next.browser('/blog/login')
    await browser.elem

).text()).toBe('[abc]')
  })

  it('should work with parameter itself in API routes', async () => {
    const text = await next.render('/api/dynamic/[slug]')
    expect(text).toBe('slug: [slug]')
  })

  it('should work with brac


 skew protection when deployed
      NEXT_DEPLOYMENT_ID: isNextStart ? 'test-deployment-id' : undefined,
      __NEXT_SUPPORTS_IMMUTABLE_ASSETS: isNextStart ? '1' : undefined,
    },
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  const

// - a bug where Edge Page routes return client assets for `new URL`s.
describe(`Handle new URL asset references`, () => {
  const { next, skipped, isTurbopack } = nextTestSetup({
    files: __dirname,
    env: {
      // rely on


ld inject propagation data for a dynamically server-side-rendered page', async () => {
      const $ = await next.render$('/app-router/dynamic-page')
      const headHtml = $.html('head')
      expect(headHtml).toContain(
        '<meta name="my-test-key-1" content="my-test-value-1">'
      )
      expect(headHtml).toContain(
        '<meta name="my-test-key-2" content="my-test-value-2">'
      )
      expect(headHtml).toMatch(
        /<meta name="my-parent-span-id" content="[a-f0-9]{16}">/
      )
      e

      const firstLoadSpanIdContent = await browser1
        .elementByCss('meta[name="my-parent-span-id"]')
        .getAttribute('content')

      const browser2 = await next.browser('/app-router/dynamic-page')
      const secondLoadSpanIdContent = await

xpect(headHtml).not.toContain('non-metadata-key-3')
    })

    it('hard loading a dynamic page twice should yield different dynamic trace data', async () => {
      const browser1 = await next.browser('/app-router/dynamic-page')


ort { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
import { trace } from '@opentelemetry/api'

export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const provider = new NodeTracerProvider()
    provider.register({
      propagator: {
        inject(context, carrier, setter) {
          setter.set(carrier, 'my-test-key-1', 'my-test-value-1')
          setter.set(carrier, 'my-test-key-2', 'my-test-value-2')
          // This non-metadata-key-3 is not going to be i

ariant'
          )
        },
        extract(context) {
          // This is a noop because we don't extract in this test
          return context
        },
        fields() {
          return [
            'my-parent-span-id',
            'my-test-key-

njected into the page
          setter.set(carrier, 'non-metadata-key-3', 'non-metadata-key-3')
          setter.set(
            carrier,
            'my-parent-span-id',
            trace.getSpanContext(context)?.spanId ?? 'inv


rver } from 'node:http'
import { SavedSpan } from './constants'

export interface Collector {
  getSpans: () => SavedSpan[]
  shutdown: () => Promise<void>
}

export async function connectCollector({
  port,
}: {
  port: number
}): Promise<Collector> {
  const spans: SavedSpan[] = []

  const server = new HttpServer(async (req, res) => {
    if (req.method !== 'POST') {
      res.writeHead(405)
      res.end()
      return
    }

    const body = await new Promise<Buffer>((resolve, reject) => {
      const

N.parse(body.toString('utf-8')) as SavedSpan[]
    const filteredSpans = newSpans.filter((span) => {
      if (span.attributes?.['next.bubble'] === true) {
        return false
      }
      return true
    })
    spans.push(...filteredSpans)
    res.statu

acc: Buffer[] = []
      req.on('data', (chunk: Buffer) => {
        acc.push(chunk)
      })
      req.on('end', () => {
        resolve(Buffer.concat(acc))
      })
      req.on('error', reject)
    })

    const newSpans = JSO


erverResponse } from 'http'
import path from 'path'
import { parse } from 'url'
import getPort from 'get-port'
import { trace } from '@opentelemetry/api'

import { register } from './instrumentation-custom-server'

register()

type EntrypointHandler = (
  req: IncomingMessage,
  res: ServerResponse,
  ctx: {
    waitUntil?: (prom: Promise<void>) => void
  }
) => Promise<unknown>

function loadEntrypointHandler(pathParts: string[]): EntrypointHandler {
  const entrypointPath = path.join(__dirname, '.next', '

ndler
}

async function main() {
  const port = await getPort()
  const hostname = 'localhost'

  require('next/dist/server/node-environment')

  const appPageHandler = loadEntrypointHandler([
    'app',
    'app',
    '[param]',
    'rsc-fetch',
    'page

server', ...pathParts)
  const mod = require(entrypointPath) as { handler?: EntrypointHandler }
  if (typeof mod.handler !== 'function') {
    throw new Error(`Entrypoint handler missing at ${entrypointPath}`)
  }
  return mod.ha


 { createServer } from 'http'
import { parse } from 'url'
import next from 'next'
import getPort from 'get-port'
import { trace } from '@opentelemetry/api'

import { register } from './instrumentation-custom-server'
register()

async function main() {
  const port = await getPort()
  const hostname = 'localhost'

  const app = next({
    dev: process.env.NODE_ENV === 'development',
    hostname,
    port,
    dir: __dirname,
  })
  const handle = app.getRequestHandler()

  await app.prepare()

  const trace

        const parsedUrl = parse(req.url!, true)
        await handle(req, res, parsedUrl)
        span.end()
      } catch (err) {
        span.recordException(err as Error)
        span.end()
        res.statusCode = 500
        res.end('Internal Server E

r = trace.getTracer('custom-server', '1.0.0')

  createServer((req, res) => {
    // Create a local parent span to simulate custom server behavior
    tracer.startActiveSpan('custom-server-request', async (span) => {
      try {


import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
import {
  ExportResult,
  ExportResultCode,
  hrTimeToMicroseconds,
} from '@opentelemetry/core'
import type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'

interface SerializedSpan {
  runtime: string | undefined
  traceId: string
  parentId: string | undefined
  traceSta

 ReadableSpan['links']
}

const serializeSpan = (span: ReadableSpan): SerializedSpan => ({
  runtime: process.env.NEXT_RUNTIME,
  traceId: span.spanContext().traceId,
  parentId: span.parentSpanId,
  traceState: span.spanContext().traceState?.serialize(),

te: string | undefined
  name: string
  id: string
  kind: number
  timestamp: number
  duration: number
  attributes: Record<string, unknown>
  status: { code: number; message?: string }
  events: ReadableSpan['events']
  links:


ces'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'

// You can use http exporter instead
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'

export function register() {
  // Next.js expects you to use to register TraceProvider. It won't work if you use NodeSDK.
  // We use registered provider to create traces insid

racerProvider({
    resource: new Resource({
      [SemanticResourceAttributes.SERVICE_NAME]: 'next-app',
    }),
  })

  provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter({})))

  // Make sure to register you provider
  provider.regi

e of Next.js internals.
  const provider = new NodeT


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

for (const { app, src, pathname, text } of [
  {
    pages: true,
    src: false,
    pathname: '/pages/param/getServerSideProps',
    text: 'Page',
  },
  {
    pages: true,
    src: true,
    pathname: '/pages/param/getServerSideProps',
    text: 'Page',
  },
  {
    app: true,
    src: false,
    pathname: '/app/param/rsc-fetch',
    text: 'Page',
  },
  {
    app: true,
    src: true,
    pathname: '/app/param/rsc-fetch',
    text: 'Page',
  },
]

les: __dirname,
      env: {
        NEXT_PUBLIC_SIMPLE_INSTRUMENT: '1',
      },
      skipDeployment: true,
      packageJson: {
        scripts: {
          'setup-dir': `mv instrumentation-minimal.ts instrumentation.ts; rm -rf ${oppositeDir}${

) {
  describe(`instrumentation ${app ? 'app' : 'pages'}${
    src ? ' src/' : ''
  }`, () => {
    const curDir = app ? 'app' : 'pages'
    const oppositeDir = app ? 'pages' : 'app'

    const { next } = nextTestSetup({
      fi


MapPropagator,
} from '@opentelemetry/api'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'
import {
  Sampler,
  SamplingDecision,
  SimpleSpanProcessor,
  SpanExporter,
  ReadableSpan,
} from '@opentelemetry/sdk-trace-base'
import {
  CompositePropagator,
  ExportResult,

: ReadableSpan): SavedSpan => ({
  runtime: process.env.NEXT_RUNTIME,
  traceId: span.spanContext().traceId,
  parentId: span.parentSpanId,
  traceState: span.spanContext().traceState?.serialize(),
  name: span.name,
  id: span.spanContext().spanId,
  kind

 ExportResultCode,
  W3CTraceContextPropagator,
  hrTimeToMicroseconds,
} from '@opentelemetry/core'

import { SavedSpan } from './constants'

const customKey = Symbol.for('opentelemetry.test/custom')

const serializeSpan = (span


      () => {
        describe('app router', () => {
          it('should handle RSC with fetch', async () => {
            await next.fetch('/app/param/rsc-fetch', env.fetchInit)

            await expectTrace(getCollector(), [
              {
                name: 'GET /app/[param]/rsc-fetch',
                attributes: {
                  'http.method': 'GET',
                  'http.route': '/app/[param]/rsc-fetch',
                  'http.status_code': 200,
                  'http.target': '/app/para

Request',
                },
                kind: 1,
                status: { code: 0 },
                traceId: env.span.traceId,
                parentId: env.span.rootParentId,
                spans: [
                  {
                    name: 'r

m/rsc-fetch',
                  'next.route': '/app/[param]/rsc-fetch',
                  'next.rsc': false,
                  'next.span_name': 'GET /app/[param]/rsc-fetch',
                  'next.span_type': 'BaseServer.handle


alid multi-match', () => {
  const { next, isNextDeploy, skipped } = nextTestSetup({
    files: __dirname,
    disableAutoSkewProtection: true,
    // The test asserts on `next.cliOutput`, expecting the local
    // `next build` failure message ("To use a multi-match in the
    // destination..."). In deploy mode `next.cliOutput` contains the
    // Vercel deploy log, which doesn't surface the same Next.js build
    // error string at the top level, so the assertions don't apply.
    skipDeployment: true,

  it('should show error for invalid multi-match', async () => {
    await next.render('/random')
    expect(next.cliOutput).toContain(
      'To use a multi-match in the destination you must add'
    )
    expect(next.cliOutput).toContain(
      'https:/

 })
  if (skipped) return
  if (isNextDeploy) return


ndalone-expect */

import { join } from 'path'
import { fetchViaHTTP } from 'next-test-utils'
import { FileRef, isNextDeploy, nextTestSetup } from 'e2e-utils'

const itif = (condition: boolean) => (condition ? it : it.skip)

describe('Middleware custom matchers i18n', () => {
  const { next } = nextTestSetup({
    files: new FileRef(join(__dirname, '../app')),
  })

  it.each(['/hello', '/en/hello', '/nl-NL/hello', '/nl-NL/about'])(
    'should match %s',
    async (path) => {
      const res = await fetchV

ut'])(
    'should not match %s',
    async (path) => {
      const res = await fetchViaHTTP(next.url, path)
      expect(res.status).toBe(404)
    }
  )

  // FIXME:
  // See https://linear.app/vercel/issue/EC-160/header-value-set-on-middleware-is-not-pro

iaHTTP(next.url, path)
      console.log(res.status)
      expect(res.status).toBe(200)
      expect(res.headers.get('x-from-middleware')).toBeDefined()
    }
  )

  it.each(['/invalid/hello', '/hello/invalid', '/about', '/en/abo


 { FileRef, nextTestSetup } from 'e2e-utils'

describe('specified tsconfig', () => {
  const { next, skipped } = nextTestSetup({
    files: new FileRef(__dirname),
    dependencies: {
      typescript: '5.4.4',
    },
  })

  if (skipped) {
    return
  }

  it('app router: allows a user-specific tsconfig via the next config', async () => {
    const html = await next.render('/')
    expect(html).toContain('bar123')
  })

  it('pages router: allows a user-specific tsconfig via the next config', async () =>

ml = await next.render('/page')
    expect(html).toContain('bar123')
  })

  it('middleware: allows a user-specific tsconfig via the next config', async () => {
    const html = await next.render('/middleware')
    expect(html).toContain('bar123')
  })
})


import { nextTestSetup, isNextDev } from 'e2e-utils'
import { readFileSync, writeFileSync } from 'fs'

describe('TypeScript Features', () => {
  describe.each([
    { label: '', testBaseUrl: true },
    { label: ' without baseUrl', testBaseUrl: false },
  ])('default behavior$label', ({ testBaseUrl }) => {
    const tsConfigPath = join(__dirname, '../../../tsconfig.json')
    let previousTsConfigJsonc: string | null = null
    beforeAll(async () => {
      if (testBaseUrl) {
        previousTsConfigJsonc =

          'packages/www/types/unfetch.d.ts'
          )
          .replace('./packages/www/components/*', 'packages/www/components/*')
          .replace('./packages/lib/a/*', 'packages/lib/a/*')
          .replace('./packages/lib/b/*', 'packages/lib/b/*')

readFileSync(tsConfigPath, 'utf-8')

        const nextTsConfigJsonc = previousTsConfigJsonc
          .replace('// baseUrl will go here', '"baseUrl": ".",')
          .replace(
            './packages/www/types/unfetch.d.ts',


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

describe('browser-shallow-navigation', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'app/pages')),
      'middleware.js': new FileRef(join(__dirname, 'app/middleware.js')),
    },
  })

  it('should render the correct page', async () => {
    const browser = await next.browser('/')

    /// do shallow push
    await browser.elementByCss('[da

llow-replace]')

    // do shadow replace
    await browser.elementByCss('[data-next-shallow-replace]').click()
    await browser.waitForElementByCss('[data-go-back]')

    // go back using history api
    await browser.elementByCss('[data-go-back]').click

ta-next-shallow-push]').click()
    await browser.waitForElementByCss('[data-next-page]')

    // go to another page
    await browser.elementByCss('[data-next-page]').click()
    await browser.waitForElementByCss('[data-next-sha


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

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

  const getNextData = async () => {
    const html = await next.render('/')
    const $ = cheerio.load(html)
    return JSON.parse($('#__NEXT_DATA__').text())
  }

  it('should not have gip or appGip in NEXT_DATA for page without getInitialProps', async () => {
    const data = awai

        'pages/index.js',
        `
        const Page = () => 'hi'
        Page.getInitialProps = () => ({ hello: 'world' })
        export default Page
      `
      )
      await retry(async () => {
        const data = await getNextData()
        expec

t getNextData()
    expect(data.gip).toBe(undefined)
    expect(data.appGip).toBe(undefined)
  })

  if (isNextDev) {
    it('should have gip in NEXT_DATA for page with getInitialProps', async () => {
      await next.patchFile(


ort { nextTestSetup } from 'e2e-utils'

describe('import-meta', () => {
  const { next, isTurbopack } = nextTestSetup({
    files: __dirname,
  })

  describe('import.meta.url', () => {
    it('should work on the server', async () => {
      const $ = await next.render$('/')
      const testData = $('#test-data').text()
      const data = JSON.parse(testData)

      if (isTurbopack) {
        expect(data.url).toStartWith('file:///')
        expect(data.url).toEndWith('/pages/index.tsx')
      } else {

= await browser.elementByCss('#test-data').text()
      const data = JSON.parse(testData)

      if (isTurbopack) {
        expect(data.url).toBe('file:///ROOT/pages/index.tsx')
      } else {
        expect(data.url).toStartWith('file:///')
        expect

   expect(data.url).toStartWith('file:///')
        expect(data.url).toEndWith('/pages/index.tsx')
      }
    })

    it('should work in browser', async () => {
      const browser = await next.browser('/')
      const testData


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

describe('i18n Support Fallback Rewrite', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not rewrite for index page', async () => {
    for (const [pathname, query] of [
      ['/', {}],
      ['/en', {}],
      ['/fr', {}],
      ['/', { hello: 'world' }],
      ['/en', { hello: 'world' }],
      ['/fr', { hello: 'world' }],
    ] as const) {
      const asPath = url.format({ pathname, query })
      const browser =

)

      await retry(async () => {
        expect(
          JSON.parse(await browser.elementByCss('#router').text())
        ).toEqual({
          index: true,
          pathname: '/',
          asPath: url.format({ pathname: '/', query }),
          quer

await next.browser(asPath)

      expect(JSON.parse(await browser.elementByCss('#router').text())).toEqual({
        index: true,
        pathname: '/',
        asPath: url.format({ pathname: '/', query }),
        query,
      }


tTestSetup } from 'e2e-utils'
import { listClientChunks, retry } from 'next-test-utils'
import fs from 'fs'
import path from 'path'

describe('swc-auto-polyfill-disabled', () => {
  const { next, isNextDev, isNextDeploy } = nextTestSetup({
    files: __dirname,
  })

  it('should render the page correctly without swcEnvOptions', async () => {
    const browser = await next.browser('/')
    await retry(async () => {
      const text = await browser.elementByCss('#result').text()
      expect(text).toBe('a_b_

Dir))
      ).filter((f) => f.endsWith('.js'))

      for (const file of jsFiles) {
        const content = fs.readFileSync(
          path.join(next.testDir, next.distDir, file),
          'utf-8'
        )
        // Skip the built-in polyfill-nomodule c

c')
    })
  })

  if (!isNextDev && !isNextDeploy) {
    it('should not include replaceAll polyfill in non-framework chunks', async () => {
      const jsFiles = (
        await listClientChunks(path.join(next.testDir, next.dist


t { FileRef, nextTestSetup, isNextDev } from 'e2e-utils'
import { join } from 'path'

// experimental.urlImports is not implemented in Turbopack
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  `Handle url imports`,
  () => {
    let staticServer
    let staticServerPort
    beforeAll(async () => {
      staticServerPort = 12345
      staticServer = await startStaticServer(
        join(__dirname, 'source'),
        undefined,
        staticServerPort
      )
    })
    afterAll(async () => {

s': new FileRef(join(__dirname, 'next.config.js')),
            pages: new FileRef(join(__dirname, 'pages')),
            public: new FileRef(join(__dirname, 'public')),
          }
        : __dirname,
      // The staticServer above doesn't work when dep

      await stopApp(staticServer)
    })

    const { next, skipped } = nextTestSetup({
      files: isNextDev
        ? {
            // exclude next.lock here, should be generated automatically in dev
            'next.config.j


gJson } from '../_testing/utils'

describe('on-request-error - basic', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  const outputLogPath = 'output-log.json'

  async function validateErrorRecord({
    errorMessage,
    url,
    renderSource,
  }: {
    errorMessage: string
    url: string
    renderSource: string | undefined
  }) {
    // Assert the instrumentation is called
    await retry(async () => {
      con

age)])
      )
      // TODO: remove custom duration in case we increase the default.
    }, 5000)

    const json = await getOutputLogJson(next, outputLogPath)
    const record = json[errorMessage]

    const { payload } = record
    const { request } = p

st recordLogLines = next.cliOutput
        .split('\n')
        .filter((log) => log.includes('[instrumentation] write-log'))
      expect(recordLogLines).toEqual(
        expect.arrayContaining([expect.stringContaining(errorMess


retry } from 'next-test-utils'
import { getOutputLogJson } from '../_testing/utils'

describe('on-request-error - otel', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    packageJson: {
      dependencies: {
        '@vercel/otel': '^1.13.0',
      },
    },
  })

  if (skipped) {
    return
  }

  const outputLogPath = 'output-log.json'

  async function validateErrorRecord({
    errorMessage,
    url,
    renderSource,
  }: {
    errorMessage: string

cludes('[instrumentation] write-log'))
      expect(recordLogLines).toEqual(
        expect.arrayContaining([expect.stringContaining(errorMessage)])
      )
      // TODO: remove custom duration in case we increase the default.
    }, 5000)

    const json

   url: string
    renderSource: string | undefined
  }) {
    // Assert the instrumentation is called
    await retry(async () => {
      const recordLogLines = next.cliOutput
        .split('\n')
        .filter((log) => log.in


ort path from 'path'

const dir = path.dirname(new URL(import.meta.url).pathname)
const logPath = path.join(dir, 'output-log.json')

export async function register() {
  fs.writeFileSync(logPath, '{}', 'utf8')
}

// Since only Node.js runtime support ISR, we can just write the error state to a file here.
// `onRequestError` will only be bundled within the Node.js runtime.
export async function onRequestError(err, request, context) {
  const payload = {
    message: err.message,
    request,
    context,
  }

arse(fs.readFileSync(logPath, 'utf8'))
    : {}

  json[payload.message] = payload

  console.log(
    `[instrumentation] write-log:${payload.message} ${payload.context.revalidateReason}`
  )
  fs.writeFileSync(logPath, JSON.stringify(json, null, 2), 'utf8

  const json = fs.existsSync(logPath)
    ? JSON.p


('on-request-error - skip-next-internal-error', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  async function assertNoNextjsInternalErrors() {
    const output = next.cliOutput
    // No navigation errors
    expect(output).not.toContain('NEXT_REDIRECT')
    expect(output).not.toContain('NEXT_NOT_FOUND')
    expect(output).not.toContain('BAILOUT_TO_CLIENT_SIDE_RENDERING')
    // No dynamic usage errors
    expect(o

tion errors
    it('should not catch server component not-found errors', async () => {
      await next.fetch('/server/not-found')
      await assertNoNextjsInternalErrors()
    })

    it('should not catch server component redirect errors', async () => {

utput).not.toContain('DYNAMIC_SERVER_USAGE')
    // No react postpone errors
    // TODO: cover PPR errors later
    expect(output).not.toContain('react.postpone')
  }

  describe('app router render', () => {
    // Server naviga


gJson } from '../_testing/utils'

describe('on-request-error - dynamic-routes', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  const outputLogPath = 'output-log.json'

  async function getErrorRecord({ errorMessage }: { errorMessage: string }) {
    // Assert the instrumentation is called
    await retry(async () => {
      const recordLogLines = next.cliOutput
        .split('\n')
        .filter((log) => log.incl

 }, 5000)

    const json = await getOutputLogJson(next, outputLogPath)
    const record = json[errorMessage]

    return record
  }

  beforeAll(async () => {
    await next.patchFile(outputLogPath, '{}')
  })

  describe('app router', () => {
    it('sho

udes('[instrumentation] write-log'))
      expect(recordLogLines).toEqual(
        expect.arrayContaining([expect.stringContaining(errorMessage)])
      )
      // TODO: remove custom duration in case we increase the default.


th'

const dir = path.join(path.dirname(new URL(import.meta.url).pathname), '../..')
const logPath = path.join(dir, 'output-log.json')

export async function POST(req) {
  let payloadString = ''
  const decoder = new TextDecoder()
  const reader = req.clone().body.getReader()
  while (true) {
    const { done, value } = await reader.read()
    if (done) {
      break
    }

    payloadString += decoder.decode(value)
  }

  const payload = JSON.parse(payloadString)

  const json = fs.existsSync(logPath)

  : {}

  if (!json[payload.message]) {
    json[payload.message] = {
      payload,
      count: 1,
    }
  } else {
    json[payload.message].count++
  }

  await fsp.writeFile(logPath, JSON.stringify(json, null, 2), 'utf8')

  console.log(`[instrumentat

? JSON.parse(await fsp.readFile(logPath, 'utf8'))


from './data.txt' with { type: 'text' }
import jsAsText from './some.js' with { type: 'text' }
import bytes from './data.bin' with { type: 'bytes' }
import jsAsBytes from './some.js' with { type: 'bytes' }
import configuredAsJsAsBytes from './configured-as-ecmascript.txt' with { type: 'bytes' }
import json from './data.json' with { type: 'json' }
import jsonAsText from './data.json' with { type: 'text' }

export async function GET(_req) {
  return Response.json(
    {
      text: {
        typeofString: typ

rray: bytes instanceof Uint8Array,
        length: bytes.length,
        content: new TextDecoder().decode(bytes),
      },
      jsAsBytes: {
        instanceofUint8Array: jsAsBytes instanceof Uint8Array,
        content: new TextDecoder().decode(jsAsByte

eof text === 'string',
        length: text.length,
        content: text,
      },
      jsAsText: {
        typeofString: typeof jsAsText === 'string',
        content: jsAsText,
      },
      bytes: {
        instanceofUint8A


import { nextTestSetup } from 'e2e-utils'

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

  it('should render server value', async () => {
    const html = await next.render('/')
    expect(html).toMatch(/the-server-value/i)
  })

  it('should render dynamic server rendered values on client mount', async () => {
    const browser = await next.browser('/')
    const text = await browser.elementByCss('#first-render').text()

    // Failure case is 'Index<!-- -->3<!--

  // should not print "invalid-dynamic-suspense" warning in browser's console
    const logs = (await browser.log()).map((log) => log.message).join('\n')
    expect(logs).not.toContain(
      'https://nextjs.org/docs/messages/invalid-dynamic-suspense'


= [
      {
        name: 'should error when domains length exceeds 50',
        config: JSON.stringify({
          images: { domains: new Array(51).fill('google.com') },
        }),
        expected:
          'Array must contain at most 50 element(s) at "images.domains"',
      },
      {
        name: 'should error when localPatterns length exceeds 25',
        config: JSON.stringify({
          images: {
            localPatterns: Array.from({ length: 26 }).map(() => ({
              pathname: '/foo/**'

    config: JSON.stringify({
          images: {
            localPatterns: [{ pathname: '/foo/**', foo: 'bar' }],
          },
        }),
        expected: `Unrecognized key(s) in object: 'foo' at "images.localPatterns[0]"`,
      },
      {
        name

,
            })),
          },
        }),
        expected:
          'Array must contain at most 25 element(s) at "images.localPatterns"',
      },
      {
        name: 'should error when localPatterns has invalid prop',


retry } from 'next-test-utils'

describe('Link with legacyBehavior', () => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return it('should skip', () => {})
  }

  describe('if the child is an <a> tag', () => {
    it('forwards the href attribute', async () => {
      const $ = await next.render$('/')
      const $a = $('a')

      expect($a.text()).toBe('About')
      expect($a.attr('href')).toBe('/about')
    })

    it('

 Page')
    })
  })

  it('works if the child is a number', async () => {
    const browser = await next.browser('/child-is-a-number')
    await browser.elementByCss('a').click()
    const title = await browser.elementByCss('h1').text()

    expect(title).

navigates correctly', async () => {
      const browser = await next.browser('/')
      await browser.elementByCss('a').click()
      const title = await browser.elementByCss('#about-page').text()

      expect(title).toBe('About


st { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'pages')),
      'next.config.js': new FileRef(join(__dirname, 'next.config.js')),
    },
    dependencies: {},
  })

  it('should restore the scroll position on navigating back', async () => {
    const browser = await next.browser('/0')
    await browser.eval(() => document.querySelector('#link').scrollIntoView())

    // check browser restoration setting
    const scrollRestoration = await browser.eval(
      () => window

window.scrollX)),
      y: Math.floor(await browser.eval(() => window.scrollY)),
    })

    // check initial value
    expect(scrollPositionMemories[0].x).not.toBe(0)
    expect(scrollPositionMemories[0].y).not.toBe(0)

    await browser.eval(`window.next

.history.scrollRestoration
    )
    expect(scrollRestoration).toBe('manual')

    const scrollPositionMemories: Array<{ x: number; y: number }> = []
    scrollPositionMemories.push({
      x: Math.floor(await browser.eval(() =>


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

const Page = ({ id }) => {
  const router = useRouter()
  const [ready, setReady] = useState(false)
  useEffect(() => {
    router.events.on('routeChangeComplete', () => {
      setReady(true)
    })
  }, [router, ready, setReady])

  return (
    <>
      <div
        style={{
          width: 10000,
          height: 10000,
          background: 'blue',
        }}
      />
      <p>{ready ? 'routeChangeComplete' : 'loading'}</p>
      <Link
        href={`/${id

marginLeft: 5000,
          width: 95000,
          display: 'block',
        }}
      >
        next page
      </Link>

hello, world

    </>
  )
}

export default Page

export const getServerSideProps = (context) => {
  const

+ 1}`}
        id="link"
        style={{


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

  it('should use react-server condition for app router server components pages', async () => {
    const rscPagesRoutes = ['/app/server', '/app/server-edge']

    for (const route of rscPagesRoutes) {
      const $ = await next.render$(route)
      expect($('#react-export-condition').text()).toBe('react-server')
      expect($('#react-dom-export-condition').text()).toBe('react-server')
    }
  })

  it('should use react

pect($('#react-export-condition').text()).toBe('default')
      expect($('#react-dom-export-condition').text()).toBe('default')
    }
  })

  it('should use react-server condition for app router custom routes', async () => {
    const customRoutes = ['/app

-server condition for app router client components pages', async () => {
    const rscPagesRoutes = ['/app/client', '/app/client-edge']

    for (const route of rscPagesRoutes) {
      const $ = await next.render$(route)
      ex


v jest */

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

describe('Requests not effected when middleware used', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, '../app/pages')),
      'middleware.js': new FileRef(join(__dirname, '../app/middleware.js')),
    },
    dependencies: {
      request: '^2.88.2',
    },
  })

  function sendRequest(method) {
    const body = !['get', 'h

= {
        'content-type': 'application/json',
        'x-custom-header': 'some value',
      }
      const res = await fetchViaHTTP(next.url, `api`, '', {
        method: method.toUpperCase(),
        headers,
        body: method.toLowerCase() !== 'get'

ead'].includes(method.toLowerCase())
      ? JSON.stringify({
          key: 'value',
        })
      : undefined
    it(`should proxy ${method} request ${
      body ? 'with body' : ''
    }`, async () => {
      const headers


th'
import { nextTestSetup } from 'e2e-utils'

describe('chrome-devtools-workspace default', () => {
  const { isNextDev, next } = nextTestSetup({
    files: path.join(__dirname, 'fixtures', 'default'),
  })

  it('should be able to connect to Chrome DevTools in dev', async () => {
    const devtoolsResponse = await next.fetch(
      '/.well-known/appspecific/com.chrome.devtools.json'
    )
    if (isNextDev) {
      const json = await devtoolsResponse.json()
      expect(json).toEqual({
        workspace:

table across reloads.
      // Otherwise you'd have to reconnect every-time.
      expect(await pageReload.json()).toEqual(json)
    } else {
      expect({ status: devtoolsResponse.status }).toEqual({ status: 404 })
    }
  })
})

describe('chrome-devtool

{
          uuid: expect.any(String),
          root: next.testDir,
        },
      })

      const pageReload = await next.fetch(
        '/.well-known/appspecific/com.chrome.devtools.json'
      )
      // The UUID should be s


mport { nextTestSetup } from 'e2e-utils'

describe('invalid-static-asset-404-app', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should return correct output with status 200 on valid asset path', async () => {
    const buildManifestPath = `/_next/static/${next.buildId}/_buildManifest.js${next.getDeploymentIdQuery()}`

    const res = await next.fetch(buildManifestPath)
    expect(res.status).toBe(200)
    const text = await res.text()
    expect(text).toContain('__BUILD_MANIF

text).toContain('Custom Not Found')
  })

  it('should return 404 with plain text when fetching invalid asset path', async () => {
    const res = await next.fetch('/_next/static/invalid-path')
    expect(res.status).toBe(404)
    const text = await res.te

EST')
  })

  it('should return custom 404 page when fetching invalid non-asset path', async () => {
    const res = await next.fetch('/invalid-path')
    expect(res.status).toBe(404)
    const text = await res.text()
    expect(


Buffer.from(await res.arrayBuffer())
  const d = sizeOf(buffer)
  expect(d.width).toBe(w)
  const lengthStr = res.headers.get('Content-Length')
  expect(lengthStr).toBe(Buffer.byteLength(buffer).toString())
  expect(isAnimated(buffer)).toBe(expectAnimated)
}

export const cleanImagesDir = async (imagesDir) => {
  console.warn('Cleaning', imagesDir)
  await fs.remove(imagesDir)
}

async function getDirSize(dir: string): Promise<number> {
  let totalSize = 0
  const entries = await fs.readdir(dir).catch(() =>

etDirSize(entryPath)
    } else {
      totalSize += stat.size
    }
  }
  return totalSize
}

async function expectAvifSmallerThanWebp(
  next: NextInstance,
  w: number,
  q: number
) {
  const qs = toQueryString({ url: '/mountains.jpg', w, q })
  const

 [] as string[])
  for (const entry of entries) {
    const entryPath = join(dir, entry)
    const stat = await fs.stat(entryPath).catch(() => null)
    if (!stat) continue
    if (stat.isDirectory()) {
      totalSize += await g


lEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==',
  'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg==',
  'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==',
  'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5/hPwAIAgL/4d1j8wAAAABJRU5ErkJggg==',
  'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P//PwAGBAL/VJiKjgAAAABJRU5ErkJggg==',
  'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lE

0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=',
]

let state = 0

export default function handler(_req, res) {
  state++
  const index = state % images.length
  const buffer = Buffer.from(images[index], 'base64')

QVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=',
  'iVBORw


t * as path from 'path'
import { nextTestSetup } from 'e2e-utils'

describe('chrome-devtools-workspace basePath', () => {
  const { isNextDev, next } = nextTestSetup({
    files: path.join(__dirname, 'fixtures', 'base-path'),
  })

  it('should be able to connect to Chrome DevTools in dev with a configured basePath', async () => {
    const devtoolsResponse = await next.fetch(
      // Chrome DevTools always requests `/`.
      '/.well-known/appspecific/com.chrome.devtools.json'
    )
    if (isNextDev) {

n = await devtoolsResponse.json()
      expect(json).toEqual({
        workspace: {
          uuid: expect.any(String),
          root: next.testDir,
        },
      })
    } else {
      expect({ status: devtoolsResponse.status }).toEqual({ status: 404 }


retry, waitFor } from 'next-test-utils'
import { getOutputLogJson } from '../_testing/utils'

const outputLogPath = 'output-log.json'

describe('on-request-error - isr', () => {
  const { next, skipped, isNextDev } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  if (isNextDev) {
    it('should skip in development mode', () => {
      // This ISR test is only applicable for production mode
    })
    return
  }

  async function matchRevalidateReason

     revalidateReason,
        },
      })
    })
  }

  describe('app router ISR', () => {
    it('should capture correct reason for stale errored page', async () => {
      await next.fetch('/app/stale')
      await waitFor(2 * 1000) // wait for revalida

(
    errorMessage: string,
    revalidateReason: string
  ) {
    await retry(async () => {
      const json = await getOutputLogJson(next, outputLogPath)
      expect(json[errorMessage]).toMatchObject({
        context: {


retry } from 'next-test-utils'
import { getOutputLogJson } from '../_testing/utils'

describe('on-request-error - server-action-error', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  const outputLogPath = 'output-log.json'

  async function validateErrorRecord({
    errorMessage,
    url,
  }: {
    errorMessage: string
    url: string
  }) {
    // Assert the instrumentation is called
    await retry(async () => {

g(errorMessage)])
      )
      // TODO: remove custom duration in case we increase the default.
    }, 5000)

    const json = await getOutputLogJson(next, outputLogPath)
    const record = json[errorMessage]

    // Assert error is recorded in the output

      const recordLogLines = next.cliOutput
        .split('\n')
        .filter((log) => log.includes('[instrumentation] write-log'))

      expect(recordLogLines).toEqual(
        expect.arrayContaining([expect.stringContainin


from 'e2e-utils'
import { fetchViaHTTP, renderViaHTTP } from 'next-test-utils'
import path from 'path'
import fs from 'fs-extra'

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

describe('i18n-ignore-rewrite-source-locale with basepath', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  test.each(locales)(
    'get public file by skipping locale in rewrite, locale: %s',
    async (locale) => {
      const res = await rende

    async (locale) => {
      const res = await renderViaHTTP(
        next.url,
        `/basepath${locale}/rewrite-api/hello`
      )
      expect(res).toContain('hello from api')
    }
  )

  // build artifacts aren't available on deploy
  if (!(global

rViaHTTP(
        next.url,
        `/basepath${locale}/rewrite-files/file.txt`
      )
      expect(res).toContain('hello from file.txt')
    }
  )

  test.each(locales)(
    'call api by skipping locale in rewrite, locale: %s',


th'

const dir = path.join(path.dirname(new URL(import.meta.url).pathname), '../..')
const logPath = path.join(dir, 'output-log.json')

export async function POST(req) {
  let payloadString = ''
  const decoder = new TextDecoder()
  const reader = req.clone().body.getReader()
  while (true) {
    const { done, value } = await reader.read()
    if (done) {
      break
    }

    payloadString += decoder.decode(value)
  }

  const payload = JSON.parse(payloadString)

  const json = fs.existsSync(logPath)

  : {}

  if (!json[payload.message]) {
    json[payload.message] = {
      payload,
      count: 1,
    }
  } else {
    json[payload.message].count++
  }

  await fsp.writeFile(logPath, JSON.stringify(json, null, 2), 'utf8')

  console.log(`[instrumentat


t() {
    return next.cliOutput.slice(previousOutputIndex)
  }

  describe('When rendering from a Server Component', () => {
    describe('Rendering <Link> directly', () => {
      it('warns if the child is a synchronous server component', async () => {
        const browser = await next.browser(
          '/validations/rsc-that-renders-link/synchronous'
        )

        if (isNextDev) {
          await expect(browser).toDisplayCollapsedRedbox(`
           [
             {
               "code": "E394",

tag.",
               "environmentLabel": "Prerender",
               "label": "Console Error",
               "source": "app/validations/rsc-that-renders-link/synchronous/page.tsx (7:7) @ Page
           >  7 |       <Link href="/about" legacyBehavior>

"description": "Using a Server Component as a direct child of \`<Link legacyBehavior>\` is not supported. If you need legacyBehavior, wrap your Server Component in a Client Component that renders the Link's \`<a>\`


 Image from 'next/image'

import img1 from '../public/animated2.png'
import img2 from '../public/äöüščří.png'
import img3 from '../public/test.avif'
import img4 from '../public/test.jpg'
import img5 from '../public/test.webp'
import img6 from '../public/animated.gif'
import img7 from '../public/grayscale.png'
import img8 from '../public/test.bmp'
import img9 from '../public/test.png'
import img11 from '../public/animated.png'
import img12 from '../public/mountains.jpg'
import img13 from '../public/test.gif'

img1} />
      <Image src={img2} />
      <Image src={img3} />
      <Image src={img4} />
      <Image src={img5} />
      <Image src={img6} />
      <Image src={img7} />
      <Image src={img8} />
      <Image src={img9} />
      <Image src={img11} />

import img14 from '../public/test.svg'
import img15 from '../public/animated.webp'
import img17 from '../public/test.ico'

export default function Home() {
  return (
    <>

Image Optimizer Home

      <Image src={


import { nextTestSetup } from 'e2e-utils'

describe('hello-world', () => {
  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(

nder('/')
    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('hel

'/')
    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.re


/* eslint-env jest */
import { createClientRouterFilter } from 'next/dist/lib/create-client-router-filter'
import { BloomFilter } from 'next/dist/shared/lib/bloom-filter'

describe('createClientRouterFilter', () => {
  it('creates a filter that does not collide with wildly different path names', () => {
    const { staticFilter, dynamicFilter } = createClientRouterFilter(
      ['/_not-found', '/a/[lang]/corporate', '/a/[lang]/gift'], // Routes are based on BOTM's app router migration project.
      []

lter.numItems,
      dynamicFilter.errorRate
    )
    dynamicFilterInstance.import(dynamicFilter)

    expect(
      staticFilterInstance.contains(
        '/all-hardcovers/no-one-can-know-1511?category=current-features'
      )
    ).toBe(false)
  })
})

)

    const staticFilterInstance = new BloomFilter(
      staticFilter.numItems,
      staticFilter.errorRate
    )
    staticFilterInstance.import(staticFilter)
    const dynamicFilterInstance = new BloomFilter(
      dynamicFi


v jest */
import { findConfig } from 'next/dist/lib/find-config'
import { join } from 'path'

const fixtureDir = join(__dirname, 'fixtures')

describe('find config', () => {
  it('should resolve rc.json', async () => {
    const config = await findConfig(join(fixtureDir, 'config-json'), 'test')
    expect(config).toEqual({ foo: 'bar' })
  })

  it('should resolve rc.js', async () => {
    const config = await findConfig(join(fixtureDir, 'config-js'), 'test')
    expect(config).toEqual({ foo: 'bar' })
  })

s', async () => {
    const config = await findConfig(join(fixtureDir, 'config-long-js'), 'test')
    expect(config).toEqual({ foo: 'bar' })
  })

  it('should resolve .config.cjs', async () => {
    const config = await findConfig(join(fixtureDir, 'config

  it('should resolve .config.json', async () => {
    const config = await findConfig(
      join(fixtureDir, 'config-long-json'),
      'test'
    )
    expect(config).toEqual({ foo: 'bar' })
  })

  it('should resolve .config.j


find-page-file'
import { normalizePagePath } from 'next/dist/shared/lib/page-path/normalize-page-path'
import { join } from 'path'

const resolveDataDir = join(__dirname, 'isolated', '_resolvedata')
const dirWithPages = join(resolveDataDir, 'readdir', 'pages')

describe('findPageFile', () => {
  it('should work', async () => {
    const pagePath = normalizePagePath('/nav/about')
    const result = await findPageFile(
      dirWithPages,
      pagePath,
      ['jsx', 'js'],
      false
    )
    expect(resul

 ['jsx', 'js'],
      false
    )
    expect(result).toMatch(/^[\\/]nested[\\/]index\.js/)
  })

  it('should prefer prefered.js before preferred/index.js', async () => {
    const pagePath = normalizePagePath('/prefered')
    const result = await findPage

t).toMatch(/^[\\/]nav[\\/]about\.js/)
  })

  it('should work with nested index.js', async () => {
    const pagePath = normalizePagePath('/nested')
    const result = await findPageFile(
      dirWithPages,
      pagePath,