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

describe('Scroll Forward Restoration Support', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should restore the scroll position on navigating forward', async () => {
    const browser = await next.browser('/another')
    await browser.elementByCss('#to-index').click()

    await retry(async () => {
      const html = await browser.eval(() => document.documentElement.innerHTML)
      expect(html).toContain('the end')

ion).toBe('manual')

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

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

    await browser.eval(

 })

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

    expect(scrollRestorat


http = require('http')
const { parse } = require('url')
const next = require('next')
const getPort = require('get-port')

async function main() {
  const dev = process.env.NEXT_TEST_MODE === 'dev'
  process.env.NODE_ENV = dev ? 'development' : 'production'

  const port = await getPort()
  const app = next({ dev, port })
  const handle = app.getRequestHandler()

  await app.prepare()

  const server = http.createServer(async (req, res) => {
    try {
      const parsedUrl = parse(req.url, true)
      const

sCode = 500
      res.end('Internal Server Error')
    }
  })

  server.once('error', (err) => {
    console.error(err)
    process.exit(1)
  })

  server.listen(port, '::', () => {
    console.log(`- Local: http://localhost:${port}`)
    console.log(`- Ne

{ pathname, query } = parsedUrl

      if (pathname.startsWith('/render')) {
        await app.render(req, res, pathname, query)
      } else {
        await handle(req, res, parsedUrl)
      }
    } catch (err) {
      res.statu


mport Link from 'next/link'

const Page = () => (

My blog

    <Link href="/[post]" as="/post-1" id="view-post-1">
      View post 1
    </Link>

    <Link
      href="/[post]/comments"
      as="/post-1/comments"
      id="view-post-1-comments"
    >
      View post 1 comments
    </Link>

    <Link
      href="/[post]/[comment]"
      as="/post-1/comment-1"
      id="view-post-1-comment-1"
    >
      View comment 1 on post 1
    </Link>

    <Link
      h

t-1?fromHome=true"
      id="view-post-1-with-query"
    >
      View post 1 with query
    </Link>
    <br />
    <Link
      href="/on-mount/[post]"
      as="/on-mount/test-w-hash#item-400"
      id="view-dynamic-with-hash"
    >
      View test with ha

ref="/blog/[post]/comment/[id]"
      as="/blog/321/comment/123"
      id="view-nested-dynamic-cmnt"
    >
      View comment 123 on blog post 321
    </Link>
    <br />
    <Link
      href="/[post]?fromHome=true"
      as="/pos


tTestSetup } from 'e2e-utils'
import cheerio from 'cheerio'

describe('disabled runtime JS', () => {
  const { next, isNextDev, isNextStart, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })
  if (skipped) return

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

  it('should not have __NEXT_DATA__ script', async () => {
    const html = await next.render('/')

    const $ = cheerio.load(html)

 () => {
      const html = await next.render('/')
      const $ = cheerio.load(html)
      expect($('script[src]').length).toBe(0)
    })

    it('should not have preload links', async () => {
      const html = await next.render('/')
      const $ = chee

 if (isNextStart) {
      expect($('script#__NEXT_DATA__').length).toBe(0)
    }
    if (isNextDev) {
      expect($('script#__NEXT_DATA__').length).toBe(1)
    }
  })

  if (isNextStart) {
    it('should not have scripts', async


y which is not supported on `NextDeployInstance`.
    skipDeployment: true,
  })
  if (skipped) return

  async function launchDevServer(
    port: number,
    opts: {
      env?: Record<string, string>
      onStderr?: (msg: string) => void
      onStdout?: (msg: string) => void
    } = {}
  ): Promise<{ child: ChildProcess; exit: Promise<any> }> {
    let child!: ChildProcess
    let ready = false
    let resolveReady!: () => void
    const readyPromise = new Promise<void>((r) => {
      resolveReady = ()

env: opts.env,
        onStdout(msg) {
          opts.onStdout?.(msg)
          if (readyPattern.test(msg)) resolveReady()
        },
        onStderr(msg) {
          opts.onStderr?.(msg)
          if (readyPattern.test(msg)) resolveReady()
        },

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

    const readyPattern = /- Local:|✓ Ready/i
    const exit = next
      .runCommand(['dev', next.testDir, '-p', String(port)], {


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

    let originalApiRoute: string
    let originalMiddleware: string
    let originalLib: string

    beforeAll(async () => {
      originalApiRoute = await next.readFile('pages/api/route.js')
      originalMiddleware = await next.readFile('middleware.js')
      // Handle lib file which might not exist or be empty
      try {
        originalLib = await nex

s', originalApiRoute)
      await next.patchFile('middleware.js', originalMiddleware)
      await next.patchFile(LIB_PATH, originalLib)
    })

    // Webpack treats `node_modules` as a "managed path" in its snapshot
    // config (see packages/next/src/bu

t.readFile(LIB_PATH)
      } catch (e) {
        // File doesn't exist, use default content
        originalLib = '// populated by tests\n'
      }
    })

    afterEach(async () => {
      await next.patchFile('pages/api/route.j


eEffect, useState } from 'react'

const NONE = '(none)'

export default function ClientComponent() {
  const [pageOrigin, setPageOrigin] = useState<string>(NONE)
  const [workerCtorUrl, setWorkerCtorUrl] = useState<string>(NONE)
  const [workerCtorError, setWorkerCtorError] = useState<string>(NONE)

  useEffect(() => {
    setPageOrigin(window.location.origin)

    // Capture the URL the Worker constructor receives (computed by the
    // turbopack runtime helper from `turbopackWorkerAssetPrefix`), so the

tring,
      options?: object
    ) {
      const urlString = typeof url === 'string' ? url : url.toString()
      setWorkerCtorUrl(urlString)
      try {
        return new OriginalWorker(url, options)
      } catch (err) {
        setWorkerCtorError(err

   // test can assert on it. Browsers reject cross-origin Worker URLs
    // synchronously, so we surface that too.
    const OriginalWorker = window.Worker
    ;(window as any).Worker = function PatchedWorker(
      url: URL | s


 type { Server } from 'http'
import { findPort } from 'next-test-utils'
import { nextTestSetup, isNextDev } from 'e2e-utils'

describe('next/dynamic with assetPrefix', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    dependencies: {
      sass: '1.54.0',
    },
    skipDeployment: true,
  })
  if (skipped) return

  let cdnPort: number
  let cdn: Server

  function createCdnProxy(targetPort: number) {
    return createServer((clientReq, clientRes) => {

          headers: clientReq.headers,
        },
        (proxyRes) => {
          proxyRes.headers['Access-Control-Allow-Origin'] =
            `http://localhost:${targetPort}`
          clientRes.writeHead(proxyRes.statusCode!, proxyRes.headers)

 const proxyPath = clientReq.url!.slice('/path-prefix'.length)
      const proxyReq = request(
        {
          hostname: 'localhost',
          port: targetPort,
          path: proxyPath,
          method: clientReq.method,


path: string) => {
    const html = await next.render(path)
    const $ = cheerio.load(html)
    const env = JSON.parse($('p').text())
    env.nextConfigEnv = $('#nextConfigEnv').text()
    env.nextConfigPublicEnv = $('#nextConfigPublicEnv').text()
    env.nextConfigNewPublicEnv = $('#nextConfigNewPublicEnv').text()
    return env
  }

  const checkEnvData = (
    data: Record<string, string | undefined>,
    didReload = false
  ) => {
    expect(data.ENV_FILE_KEY).toBe('env')
    expect(data.LOCAL_ENV_FILE

    expect(data.TEST_ENV_FILE_KEY).toBe(undefined)
    expect(data.LOCAL_TEST_ENV_FILE_KEY).toBe(undefined)
    expect(data.PRODUCTION_ENV_FILE_KEY).toBe(
      isNextDev ? undefined : 'production'
    )
    expect(data.LOCAL_PRODUCTION_ENV_FILE_KEY).toBe

_KEY).toBe('localenv')
    expect(data.DEVELOPMENT_ENV_FILE_KEY).toBe(
      isNextDev ? 'development' : undefined
    )
    expect(data.LOCAL_DEVELOPMENT_ENV_FILE_KEY).toBe(
      isNextDev ? 'localdevelopment' : undefined
    )


on('error', (err) => {
        console.error(err)
        socket.close()
        reject()
      })
    })

    await retry(() => {
      expect(messages.length).toBeGreaterThan(0)
    })
    ws.close()
    expect([...externalServerHits]).toEqual(['/_next/hmr?page=/about'])
  })

  it('should successfully rewrite a WebSocket request to a page', async () => {
    const messages = []
    try {
      const ws = await new Promise<WebSocket>((resolve, reject) => {
        let socket = new WebSocket(
          `ws

rr) => {
          console.error(err)
          socket.close()
          reject()
        })
      })
      ws.close()
    } catch (err) {
      messages.push(err)
    }
    expect(next.cliOutput).not.toContain('unhandledRejection')
  })

  it('should not

://localhost:${next.appPort}/websocket-to-page`
        )
        socket.on('message', (data) => {
          messages.push(data.toString())
        })
        socket.on('open', () => resolve(socket))
        socket.on('error', (e


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

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

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

      <p id="ro

 without params
  if (!params || !params.slug) {
    throw new Error(`missing params ${JSON.stringify(params)}`)
  }

  if (locale === 'en' || locale === 'nl') {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      params,
      loca

uter-as-path">{router.asPath}

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

    </>
  )
}

export const getStaticProps = ({ params, locale, locales }) => {
  // ensure getStaticProps isn't called


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

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathname}

{router.asPath}

.slug) {
    throw new Error(`missing params ${JSON.stringify(params)}`)
  }

  if (locale === 'en' || locale === 'nl') {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      params,
      locale,
      locales,
    },
  }
}

export

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

export const getStaticProps = ({ params, locale, locales }) => {
  // ensure getStaticProps isn't called without params
  if (!params || !params


e/proxy'

describe('testmode', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    dependencies: require('./package.json').dependencies,
  })

  if (skipped) {
    return
  }

  let proxyServer: Awaited<ReturnType<typeof createProxyServer>>

  beforeEach(async () => {
    proxyServer = await createProxyServer({
      onFetch: async (testData, request) => {
        if (
          request.method === 'GET' &&
          [
            'https://example.com/',

t.url === 'https://example.com/middleware'
        ) {
          return new Response(`middleware-${testData}`)
        }
        return undefined
      },
    })
  })

  afterEach(async () => {
    proxyServer.close()
  })

  const fetchForTest = async (ur

          'https://next-data-api-endpoint.vercel.app/api/random',
          ].includes(request.url)
        ) {
          return new Response(testData)
        }
        if (
          request.method === 'GET' &&
          reques


    const readyPromise = new Promise<void>((r) => {
      resolveReady = () => {
        if (!ready) {
          ready = true
          r()
        }
      }
    })

    const readyPattern = /- Local:|✓ Ready/i
    const exit = next
      .runCommand(['dev', next.testDir, '-p', String(port)], {
        env: opts.env,
        onStdout(msg) {
          opts.onStdout?.(msg)
          if (readyPattern.test(msg)) resolveReady()
        },
        onStderr(msg) {
          opts.onStderr?.(msg)
          if (ready

NextStart ? describe : describe.skip)('production mode', () => {
    it('detects rewrites, headers, and redirects for next build', async () => {
      await fs.rename(
        path.join(next.testDir, 'next.config.custom-routes'),
        path.join(next.tes

Pattern.test(msg)) resolveReady()
        },
        instance: (p) => {
          child = p
        },
      })
      .finally(() => {
        resolveReady()
      })

    await readyPromise
    return { child, exit }
  }

  ;(is


etry feature itself is not React-version-specific, so
// skipping under React 18 is fine until the underlying build/server lifecycle
// race is fixed.
;(isReact18 ? describe.skip : describe)('Telemetry CLI', () => {
  const { next, isNextStart, isTurbopack, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  it('can print telemetry status', async () => {
    const { stdout } = await next.runCommand(['telemetry'])
    expect(stdout).t

t(stdout).toMatch(/Success/)
    expect(stdout).toMatch(/Status: Enabled/)
  })

  it('can disable telemetry with flag', async () => {
    const { stdout } = await next.runCommand(['telemetry', '--disable'], {
      env: {
        NEXT_TELEMETRY_DISABLED:

oMatch(/Status: .*/)
  })

  it('can enable telemetry with flag', async () => {
    const { stdout } = await next.runCommand(['telemetry', '--enable'], {
      env: {
        NEXT_TELEMETRY_DISABLED: '',
      },
    })
    expec


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

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

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

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

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


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

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

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

  return (
    <>

gsp page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

      <p id="rout

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

  if (params && params.slug === 'mixed-not-found-redirect') {
    return

er-pathname">{router.pathname}

{router.asPath}

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

    </>
  )
}

export const getStaticProps = ({ params, locale, local


from 'e2e-utils'

describe('Dynamic Routing with src dir', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should render normal route', async () => {
    const html = await next.render('/')
    expect(html).toMatch(/my blog/i)
  })

  it('should render another normal route', async () => {
    const html = await next.render('/another')
    expect(html).toMatch(/hello from another/)
  })

  it('should render dynamic page', async () => {
    const html = await next.render('/post-1'

  })

  it('should render nested dynamic page', async () => {
    const html = await next.render('/post-1/comment-1')
    expect(html).toMatch(/i am.*comment-1.*on.*post-1/i)
  })

  it('should navigate to a dynamic page successfully', async () => {
    co

)
    expect(html).toMatch(/this is.*?post-1/i)
  })

  it('should prioritize a non-dynamic page', async () => {
    const html = await next.render('/post-1/comments')
    expect(html).toMatch(/show comments for.*post-1.*here/i)


xDescription,
} from 'next-test-utils'
import { nextTestSetup } from 'e2e-utils'

describe('Conflict between app file and pages file', () => {
  const { next, isNextDev, isNextStart, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    skipStart: true,
  })

  if (skipped) {
    return
  }

  if (isNextStart) {
    it('should print error for conflicting app/page', async () => {
      const { cliOutput } = await next.build()
      if (process.env.IS_TURBOPACK_TEST) {
        expect

xpect(cliOutput).toMatch(
          /Conflicting app and page files? (were|was) found/
        )

        for (const [pagePath, appPath] of [
          ['pages/index.js', 'app/page.js'],
          ['pages/another.js', 'app/another/page.js'],
        ]) {

(cliOutput).toContain(
          'App Router and Pages Router both match path: /'
        )
        expect(cliOutput).toContain(
          'App Router and Pages Router both match path: /another'
        )
      } else {
        e


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

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

  return (
    <>

developments page

{JSON.stringify(props)}

{router.locale}

{router.defaultLocale}

{JSON.stringify(router.locales)}

{JSON.stringify(router.query)}

{router.pathn

}

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

    </>
  )
}

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


variables = [
  'PROCESS_ENV_KEY',
  'ENV_FILE_KEY',
  'ENV_FILE_EMPTY_FIRST',
  'ENV_FILE_PROCESS_ENV',
  'LOCAL_ENV_FILE_KEY',
  'ENV_FILE_LOCAL_OVERRIDE_TEST',
  'PRODUCTION_ENV_FILE_KEY',
  'LOCAL_PRODUCTION_ENV_FILE_KEY',
  'DEVELOPMENT_ENV_FILE_KEY',
  'LOCAL_DEVELOPMENT_ENV_FILE_KEY',
  'ENV_FILE_DEVELOPMENT_OVERRIDE_TEST',
  'ENV_FILE_DEVELOPMENT_LOCAL_OVERRIDEOVERRIDE_TEST',
  'ENV_FILE_PRODUCTION_OVERRIDEOVERRIDE_TEST',
  'ENV_FILE_PRODUCTION_LOCAL_OVERRIDEOVERRIDE_TEST',
  'TEST_ENV_FILE_KEY',

NV_KEY',
  'NEW_ENV_LOCAL_KEY',
  'NEW_ENV_DEV_KEY',
  'NEXT_PUBLIC_HELLO_WORLD',
]

export default async function handler(req, res) {
  const items = {
    nextConfigEnv: process.env.nextConfigEnv,
    nextConfigPublicEnv: process.env.nextConfigPublicEnv,

'LOCAL_TEST_ENV_FILE_KEY',
  'ENV_FILE_TEST_OVERRIDE_TEST',
  'ENV_FILE_TEST_LOCAL_OVERRIDEOVERRIDE_TEST',
  'ENV_FILE_EXPANDED',
  'ENV_FILE_EXPANDED_CONCAT',
  'ENV_FILE_EXPANDED_ESCAPED',
  'ENV_FILE_KEY_EXCLAMATION',
  'NEW_E


_TEST
const describeTurbopack =
  isTurbopack && !isNextDeploy ? describe : describe.skip

// CORS so cross-origin script tags from `assetPrefix` can be fetched. Workers
// are NOT covered by CORS — `new Worker(crossOriginUrl)` is rejected
// regardless — so this only unblocks regular script loading.
const corsHeadersConfig = `
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [{ key: 'Access-Control-Allow-Origin', value: '*' }],
      },
    ]
  },`

/**
 * Real cross-ori

t.js server bound to all interfaces.
 *
 * The fixture intercepts `new Worker()` to capture the URL the turbopack
 * runtime helper resolved from `turbopackWorkerAssetPrefix`, so each test
 * can assert on that URL directly.
 */
describeTurbopack('turbopac

gin setup: the page is served at `http://localhost:PORT/`,
 * `assetPrefix` points to `http://127.0.0.1:PORT` (different origin —
 * browsers treat `localhost` and `127.0.0.1` as distinct origins). Both
 * resolve to the same Nex


xtTestSetup({
      files: __dirname,
      // Deployed environment has it's own configured limits.
      skipDeployment: true,
    })

    if (skipped) return

    it('should accept request body over 10MB but only buffer up to limit', async () => {
      const bodySize = 11 * 1024 * 1024 // 11MB
      const body = 'x'.repeat(bodySize)

      const res = await fetchViaHTTP(
        next.url,
        '/api/echo',
        {},
        {
          body,
          method: 'POST',
        }
      )

      expect(

Equal(10 * 1024 * 1024)
      expect(responseBody.bodySize).toBeLessThan(bodySize)
      expect(next.cliOutput).toContain(
        'Request body exceeded 10MB for /api/echo'
      )
    })

    it('should accept request body at exactly 10MB', async () => {

res.status).toBe(200)
      const responseBody = await res.json()
      expect(responseBody.message).toBe('Hello World')
      // Should only buffer up to 10MB, not the full 11MB
      expect(responseBody.bodySize).toBeLessThanOr


sNextDeploy } from 'e2e-utils'
import { pathExists, readdir } from 'fs-extra'
import { join } from 'path'

describe('CPU Profiling - next build', () => {
  const { next, isNextDev, skipped, isTurbopack } = nextTestSetup({
    files: __dirname,
    buildCommand: 'pnpm next build --experimental-cpu-prof',
    dependencies: {},
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  // CPU profiling only works with local `next build`, not dev or deploy modes
  if (isNextDev || isNextDeploy

r build', async () => {
    const profileDir = join(next.testDir, '.next-profiles')

    const profileDirExists = await pathExists(profileDir)
    expect(profileDirExists).toBe(true)

    const files = await readdir(profileDir)
    const cpuProfiles = file

 || skipped) {
    it('skip for development/deploy mode', () => {})
    return
  }

  beforeAll(async () => {
    // Run the build with CPU profiling enabled
    await next.build()
  })

  it('should create CPU profile files afte


tTestSetup } from 'e2e-utils'
import { pathExists, readdir } from 'fs-extra'
import { join } from 'path'
import { retry } from 'next-test-utils'

describe('CPU Profiling - next dev', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
    startCommand: 'pnpm next dev --experimental-cpu-prof',
    dependencies: {},
  })

  if (!isNextDev) {
    it('skip for production mode', () => {})
    return
  }

  it('should create CPU profile files on exit', async () => {
    const profileDir =

ILL doesn't allow cleanup)
    await next.stop('SIGTERM')

    // Retry until profile files are written
    const cpuProfiles = await retry(async () => {
      const profileDirExists = await pathExists(profileDir)
      expect(profileDirExists).toBe(true)

join(next.testDir, '.next-profiles')

    // Make a request to ensure the server is running
    const res = await next.fetch('/')
    expect(res.status).toBe(200)

    // Stop the server with SIGTERM to trigger profile save (SIGK


sNextDeploy } from 'e2e-utils'
import { pathExists, readdir } from 'fs-extra'
import { join } from 'path'
import { retry } from 'next-test-utils'

describe('CPU Profiling - next start', () => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    startCommand: 'pnpm next start --experimental-cpu-prof',
    dependencies: {},
    skipStart: true, // Skip auto-start to avoid failure in dev/deploy mode
  })

  // CPU profiling only works with local `next start`, not dev or deploy mod

 => {
    const profileDir = join(next.testDir, '.next-profiles')

    // Make a request to ensure the server is running
    const res = await next.fetch('/')
    expect(res.status).toBe(200)

    // Stop the server with SIGTERM to trigger profile save (SI

es
  if (isNextDev || isNextDeploy || skipped) {
    it('skip for development/deploy mode', () => {})
    return
  }

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

  it('should create CPU profile files on exit', async ()


import { nextTestSetup } from 'e2e-utils'

describe('styled-jsx', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    dependencies: {
      'styled-jsx': '5.0.0', // styled-jsx on user side
    },
  })

  if (skipped) {
    return
  }

  it('should contain styled-jsx styles during SSR', async () => {
    const html = await next.render('/')
    expect(html).toMatch(/color:.*?red/)
    expect(html).toMatch(/color:.*?cyan/)
  })

  it('should render styles du

t('should render styles inside TypeScript', async () => {
    const browser = await next.browser('/typescript')
    const color = await browser.eval(
      `getComputedStyle(document.querySelector('button')).color`
    )

    expect(color).toMatch('255, 0,

ring CSR', async () => {
    const browser = await next.browser('/')
    const color = await browser.eval(
      `getComputedStyle(document.querySelector('button')).color`
    )

    expect(color).toMatch('0, 255, 255')
  })

  i


t.meta.glob is a Turbopack-only feature; skip under webpack
const testFn = process.env.IS_WEBPACK_TEST ? describe.skip : describe

testFn('import-meta-glob', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) return

  it('should resolve lazy glob modules', async () => {
    const $ = await next.render$('/')
    const lazyKeys = JSON.parse($('#lazy-keys').text())
    expect(lazyKeys).toEqual([
      './modules/bar.ts',
      './modules/fo

: 'skip',
    })
  })

  it('should resolve eager glob modules', async () => {
    const $ = await next.render$('/')
    const eagerKeys = JSON.parse($('#eager-keys').text())
    expect(eagerKeys).toEqual([
      './modules/bar.ts',
      './modules/foo.ts

o.ts',
      './modules/skip.ts',
    ])

    const lazyResults = JSON.parse($('#lazy-results').text())
    expect(lazyResults).toEqual({
      './modules/bar.ts': 'bar',
      './modules/foo.ts': 'foo',
      './modules/skip.ts'


./modules/*.ts')

// Eager glob
const eagerModules = import.meta.glob('./modules/*.ts', { eager: true })

// Named import (eager)
const defaultExports = import.meta.glob('./modules/*.ts', {
  import: 'default',
  eager: true,
})

// Negative pattern
const filteredModules = import.meta.glob(['./modules/*.ts', '!**/skip.ts'], {
  eager: true,
})

// Multiple patterns (modules + other)
const multiModules = import.meta.glob(['./modules/*.ts', './other/*.ts'], {
  eager: true,
})

export default async function P

 (mod as any).name
  }

  // Get eager module names
  const eagerKeys = Object.keys(eagerModules).sort()
  const eagerResults: Record<string, string> = {}
  for (const key of eagerKeys) {
    eagerResults[key] = (eagerModules[key] as any).name
  }

  // Ge

age() {
  // Resolve lazy modules
  const lazyKeys = Object.keys(lazyModules).sort()
  const lazyResults: Record<string, string> = {}
  for (const key of lazyKeys) {
    const mod = await lazyModules[key]()
    lazyResults[key] =


ort { FileRef, nextTestSetup } from 'e2e-utils'
import { spawnSync } from 'child_process'

function createTemporaryFixture(fixtureName: string) {
  const fixturePath = join(__dirname, fixtureName)
  const stat = statSync(fixturePath)
  if (!stat.isDirectory()) {
    throw new Error(`Fixture ${fixtureName} is not a directory.`)
  }

  const dir = mkdtempSync(join(tmpdir(), fixtureName))
  cpSync(fixturePath, dir, { recursive: true })
  return dir
}

describe.skip('next test', () => {
  const { next: basicExa

 `experimental-test` mode
    skipDeployment: true,
  })

  if (skipped) return

  afterAll(async () => {
    await basicExample.destroy()
  })

  describe('first time setup', () => {
    it.each([['first-time-setup-js'], ['first-time-setup-ts']])(
      '

mple, skipped } = nextTestSetup({
    files: new FileRef(join(__dirname, 'basic-example')),
    dependencies: {
      '@playwright/test': '1.43.1',
    },
    skipStart: true,
    // This doesn't need to be deployed as it's using


'start',
    assertions: (getOutput: () => string) => void | Promise<void>
  ) {
    if (mode === 'dev') {
      await next.start()
      try {
        await next.fetch('/').catch(() => {})
        await retry(async () => {
          await assertions(() => next.cliOutput)
        })
      } finally {
        await next.stop()
      }
    } else {
      const { cliOutput } = await next.build()
      const fixed = cliOutput
      await retry(async () => {
        await assertions(() => fixed)
      })
    }

) => {
      await writeConfig(
        [
          {
            source: `/:path*`,
            headers: [],
          },
        ],
        'headers'
      )
      await captureStderr(mode, (getOutput) => {
        const stderr = getOutput()
        expe

 }

  afterAll(async () => {
    await next.patchFile('next.config.js', `module.exports = {}\n`)
  })

  function runTests(mode: 'dev' | 'start') {
    it('should error when empty headers array is present on header item', async (


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

describe('handle-non-hoisted-swc-helpers', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/index.js': `
        export default function Page() {
          return
hello world

        }

        export function getServerSideProps() {
          const helper = require('@swc/helpers/_/_object_spread')
          console.log(helper)
          return {
            props: {
              now: D

 },
    installCommand:
      'npm install; mkdir -p node_modules/next/node_modules/@swc; mv node_modules/@swc/helpers node_modules/next/node_modules/@swc/',
    buildCommand: 'npm run build',
    startCommand: isNextDev ? 'npm run dev' : 'npm run start',

ate.now()
            }
          }
        }
      `,
    },
    packageJson: {
      packageManager: 'npm@10.9.2',
      scripts: {
        build: 'next build',
        dev: 'next dev',
        start: 'next start',
      },


RewriteTo,
} from './shared-tests.util'
import { nextTestSetup, isNextDev } from 'e2e-utils'

// we don't need to exhaustively test this, just do some basic sanity checks
// for use in combiantion with basePath
;(isNextDev ? describe : describe.skip)(
  'Trailing slashes in development mode, with basepath, trailingSlash: true',
  () => {
    const { next } = nextTestSetup({
      files: __dirname,
      nextConfig: {
        trailingSlash: true,
        basePath: '/docs',
      },
    })

    testShouldRedi

      ['/docs', '/docs/'],
      ['/docs/catch-all/hello/world', '/docs/catch-all/hello/world/'],
      ['/docs/catch-all/hello.world/', '/docs/catch-all/hello.world'],
    ])

    testLinkShouldRewriteTo(next, [
      ['/docs/linker?href=/about', '/docs/a

rect(next, [
      ['/docs/about', '/docs/about/'],


.test.ts` so that both test suites can be run in parallel.

import cheerio from 'cheerio'
import type { NextInstance, Playwright } from 'e2e-utils'

export function testShouldRedirect(
  next: NextInstance,
  expectations: [string, string][]
) {
  it.each(expectations)(
    '%s should redirect to %s',
    async (route, expectedLocation) => {
      const res = await next.fetch(route, { redirect: 'manual' })
      expect(res.status).toBe(308)
      const { pathname } = new URL(res.headers.get('location'))

th %s',
    async (route, expectedPage, expectedRouterPath) => {
      const res = await next.fetch(route, { redirect: 'error' })
      expect(res.status).toBe(200)
      const $ = cheerio.load(await res.text())
      expect($('#page-marker').text()).toBe(

   expect(pathname).toBe(expectedLocation)
    }
  )
}

export function testShouldResolve(
  next: NextInstance,
  expectations: [string, string, string][]
) {
  it.each(expectations)(
    '%s should resolve to %s, with router pa


ndalone-expect */

import {
  testShouldRedirect,
  testLinkShouldRewriteTo,
  testShouldResolve,
  testExternalLinkShouldRewriteTo,
} from './shared-tests.util'
import { nextTestSetup } from 'e2e-utils'
import { join } from 'path'

describe('Trailing slashes with trailingSlash: true', () => {
  const { next, isNextStart } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      trailingSlash: true,
    },
  })

  testShouldRedirect(next, [
    ['/about', '/about/'],
    ['/catch-all/hello/world', '/

s', '/about'],
    [
      '/catch-all/hello/world/',
      '/catch-all/[...slug].js',
      '/catch-all/[...slug]',
    ],
    ['/about/?hello=world', '/about.js', '/about'],
  ])

  testLinkShouldRewriteTo(next, [
    ['/linker?href=/', '/'],
    ['/link

catch-all/hello/world/'],
    ['/catch-all/hello.world/', '/catch-all/hello.world'],
  ])

  testShouldResolve(next, [
    // visited url, expected page, expected router path
    ['/', '/index.js', '/'],
    ['/about/', '/about.j


ndalone-expect */

import {
  testShouldRedirect,
  testLinkShouldRewriteTo,
  testShouldResolve,
  testExternalLinkShouldRewriteTo,
} from './shared-tests.util'
import { nextTestSetup } from 'e2e-utils'
import { join } from 'path'

describe('Trailing slashes with trailingSlash: false', () => {
  const { next, isNextStart } = nextTestSetup({
    files: __dirname,
    nextConfig: {
      trailingSlash: false,
    },
  })

  testShouldRedirect(next, [
    ['/about/', '/about'],
    ['/catch-all/hello/world/',

js', '/about'],
    [
      '/catch-all/hello/world',
      '/catch-all/[...slug].js',
      '/catch-all/[...slug]',
    ],
    ['/about?hello=world', '/about.js', '/about'],
  ])

  testLinkShouldRewriteTo(next, [
    ['/linker?href=/', '/'],
    ['/linke

 '/catch-all/hello/world'],
    ['/catch-all/hello.world/', '/catch-all/hello.world'],
  ])

  testShouldResolve(next, [
    // visited url, expected page, expected router path
    ['/', '/index.js', '/'],
    ['/about', '/about.


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

describe('deprecation-warnings', () => {
  describe('without next.config.js', () => {
    const { next } = nextTestSetup({
      files: path.join(__dirname, 'fixtures/no-config'),
      skipStart: true,
    })

    it('should not emit any deprecation warnings when no config file exists', async () => {
      await next.start()

      const logs = next.cliOutput
      expect(logs).not.toContain('deprecated')
      expect(logs).n

res/with-deprecated-config'),
      skipStart: true,
    })

    it('should emit deprecation warnings for explicitly configured deprecated options', async () => {
      await next.start()

      await retry(async () => {
        const logs = next.cliOutput

ot.toContain('has been renamed')
      expect(logs).not.toContain('no longer needed')
    })
  })

  describe('with deprecated config options', () => {
    const { next } = nextTestSetup({
      files: path.join(__dirname, 'fixtu


io from 'cheerio'
import { FileRef, nextTestSetup } from 'e2e-utils'
import { renderViaHTTP } from 'next-test-utils'
import { join } from 'path'

const mockedGoogleFontResponses = require.resolve(
  './google-font-mocked-responses.js'
)

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

  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'basepath/pages')),
      'next.c

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

    // Preconnect
    expect($('link[rel="preconnect"]').length).toBe(0)

    // Preload
    expect($('link[as="font"]').length).toBe(1)
    expect($('link[as="font"]').get(0).a

onfig.js': new FileRef(join(__dirname, 'basepath/next.config.js')),
    },
    env: {
      NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
    },
  })

  test('preload correct files', async () => {
    const html =


import { join } from 'path'

const mockedGoogleFontResponses = require.resolve(
  './google-font-mocked-responses.js'
)

describe('next/font/google fetch error', () => {
  const isDev = (global as any).isNextDev

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

  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, 'google-fetch-error/pages')),
    },
    env: {
      NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFon

ser('/')

      const ascentOverride = await browser.eval(
        'Array.from(document.fonts.values()).find(font => font.family.includes("Inter Fallback")).ascentOverride'
      )
      expect(ascentOverride).toMatchInlineSnapshot(`"90.44%"`)

      const

tResponses,
    },
    skipStart: true,
  })

  if (isDev) {
    it('should use a fallback font in dev', async () => {
      await next.start()
      const outputIndex = next.cliOutput.length
      const browser = await next.brow


BA-UvWbX2vVnXBbObj2OVTS2mu0SC55K5gw.woff2) format('woff2');
  unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
/* vietnamese */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu0SC55K5gw.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1

BA-UvWbX2vVnXBbObj2OVTSGmu0SC55K5gw.woff2) format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;

EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/opensans/v34/memvYaGs126MiZp


     // Turbopack includes the file hash
      /\/_next\/static\/(immutable\/)?media\/(.*)\.p\.(.*)\.woff2/
    )
  } else {
    expect(href).toMatch(/\/_next\/static\/(immutable\/)?media\/(.*)\.p\.woff2/)
  }
}

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

  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, `app/pages`)),
      components: new FileRef(join(__dirname, `app/componen

bal as any).isNextDev) {
    it('should use production cache control for fonts', async () => {
      const $ = await next.render$('/')
      const link = $('[rel="preload"][as="font"]').attr('href')
      expect(link).toBeDefined()
      const res = await

ts`)),
      fonts: new FileRef(join(__dirname, `app/fonts`)),
    },
    dependencies: {
      '@next/font': 'canary',
    },
    env: {
      NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
    },
  })

  if ((glo


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

const mockedGoogleFontResponses = require.resolve(
  './google-font-mocked-responses.js'
)

const isDev = (global as any).isNextDev

describe('next/font/google with-font-declarations-file', () => {
  if ((global as any).isNextDeploy) {
    it('should skip next deploy for now', () => {})
    return
  }

  const { next } = nextTestSetup({
    files: join(__dirname, 'with-font-declarations-file'),
    env: {
      NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFon

length).toBe(0)

    if (isDev) {
      // In dev all fonts will be preloaded since it's before DCE
      expect($('link[as="font"]').length).toBe(4)
    } else {
      // Preload
      expect($('link[as="font"]').length).toBe(
        // TODO: Remove this

tResponses,
    },
  })

  test('preload correct files at /inter', async () => {
    const html = await renderViaHTTP(next.url, '/inter')
    const $ = cheerio.load(html)

    // Preconnect
    expect($('link[rel="preconnect"]').


import { findPort, renderViaHTTP, fetchViaHTTP } from 'next-test-utils'
import { join } from 'path'
import spawn from 'cross-spawn'

describe('next/font/google with proxy', () => {
  if ((global as any).isNextDeploy) {
    it('should skip next deploy', () => {})
    return
  }

  const { next } = nextTestSetup({
    files: new FileRef(join(__dirname, 'with-proxy')),
    skipStart: true,
  })

  let proxy: any
  let SERVER_PORT: number

  beforeAll(async () => {
    const PROXY_PORT = await findPort()
    SE

ERVER_PORT.toString(),
      },
    })

    await next.start({
      env: { http_proxy: 'http://localhost:' + PROXY_PORT },
    })
  })
  afterAll(() => {
    proxy?.kill('SIGKILL')
  })

  // Reqwest doesn't seem to fully work with https proxy
  ;(process

RVER_PORT = await findPort()

    proxy = spawn('node', [require.resolve('./with-proxy/server.js')], {
      stdio: 'inherit',
      env: {
        ...process.env,
        PROXY_PORT: PROXY_PORT.toString(),
        SERVER_PORT: S


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

const mockedGoogleFontResponses = require.resolve(
  './google-font-mocked-responses.js'
)

describe('next/font/google without-preloaded-fonts without _app', () => {
  if ((global as any).isNextDeploy) {
    it('should skip next deploy for now', () => {})
    return
  }

  const { next } = nextTestSetup({
    files: {
      'pages/no-preload.js': new FileRef(
        join(__dirname, 'without-preloaded-fonts/pages/no-preload.js')
      ),
      'pages/w

preload', async () => {
    const html = await renderViaHTTP(next.url, '/no-preload')
    const $ = cheerio.load(html)

    // Preconnect
    expect($('link[rel="preconnect"]').length).toBe(1)
    expect($('link[rel="preconnect"]').get(0).attribs).toEqual(

ithout-fonts.js': new FileRef(
        join(__dirname, 'without-preloaded-fonts/pages/without-fonts.js')
      ),
    },
    env: {
      NEXT_FONT_GOOGLE_MOCKED_RESPONSES: mockedGoogleFontResponses,
    },
  })

  test('without


ire('next/dist/compiled/http-proxy')

const PROXY_PORT = process.env.PROXY_PORT
const SERVER_PORT = process.env.SERVER_PORT

httpProxy
  .createProxyServer({ target: 'http://localhost:' + SERVER_PORT })
  .listen(PROXY_PORT)

const cssResponse = `
/* cyrillic-ext */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/oswald/v49/TK3iWkUHHAIjg752FD8Gl-1PK62t.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80

3iWkUHHAIjg752HT8Gl-1PK62t.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: u

-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Oswald';
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/oswald/v49/TK


o } from 'next/font/google'
import localFont from 'next/font/local'

const firaCode = Fira_Code({ variable: '--fira-code', subsets: ['latin'] })
const roboto = Roboto({
  weight: '100',
  style: 'italic',
  display: 'swap',
  preload: true,
  variable: '--roboto-100-italic',
  subsets: ['latin'],
})
const myFont = localFont({
  src: '../fonts/my-font.woff2',
  preload: false,
  variable: '--my-font',
})

export default function WithFonts() {
  return (
    <>
      {/* Fira Code Variable */}
      <div

{ fontFamily: 'var(--fira-code)' }}
      >
        Without variables
      </div>

      {/* Roboto 100 Italic */}
      <div
        id="variables-roboto-100-italic"
        className={roboto.variable}
        style={{ fontFamily: 'var(--roboto-100-itali

    id="variables-fira-code"
        className={firaCode.variable}
        style={{ fontFamily: 'var(--fira-code)' }}
      >
        With variables
      </div>
      <div
        id="without-variables-fira-code"
        style={


import localFont from 'next/font/local'
import { Open_Sans } from 'next/font/google'
const openSans = Open_Sans({
  fallback: ['system-ui', 'Arial'],
  variable: '--open-sans',
  adjustFontFallback: false,
  subsets: ['latin'],
})

const myFont = localFont({
  fallback: ['system-ui', 'Arial'],
  src: '../fonts/my-font.woff2',
  adjustFontFallback: false,
  subsets: ['latin'],
})

export default function WithFonts() {
  return (
    <>
      <div id="with-fallback-fonts-classname" className={openSans.classNa

tyle={{ fontFamily: 'var(--open-sans)' }}
        className={openSans.variable}
      >
        {JSON.stringify(openSans)}
      </div>
      <div id="with-fallback-local" className={myFont.className}>
        {JSON.stringify(myFont)}
      </div>
    </>

me}>
        {JSON.stringify(openSans)}
      </div>
      <div id="with-fallback-fonts-style" style={openSans.style}>
        {JSON.stringify(openSans)}
      </div>
      <div
        id="with-fallback-fonts-variable"
        s


unces, Indie_Flower, Roboto } from 'next/font/google'

const indieFlower = Indie_Flower({
  weight: '400',
  preload: false,
  subsets: ['latin'],
})
const fraunces = Fraunces({ weight: '400', preload: false, subsets: ['latin'] })

const robotoMultiple = Roboto({
  weight: ['900', '100'],
  style: ['normal', 'italic'],
  subsets: ['latin'],
})
const frauncesMultiple = Fraunces({
  style: ['italic', 'normal'],
  axes: ['SOFT', 'WONK', 'opsz'],
  subsets: ['latin'],
})

const frauncesMultipleWeights = Fraunce

        {JSON.stringify(fraunces)}

        {JSON.stringify(robotoMultiple)}

      <

s({
  weight: ['100', '400', '900'],
  subsets: ['latin'],
})

export default function WithFonts() {
  return (
    <>
      <div id="first-google-font" className={indieFlower.className}>
        {JSON.stringify(indieFlower)}


  style: 'italic',
  weight: '100',
  fallback: ['system-ui'],
  adjustFontFallback: 'Times New Roman',
  declarations: [{ prop: 'ascent-override', value: '90%' }],
})
const myFont2 = localFont({
  src: '../fonts/my-other-font.woff2',
  preload: false,
  variable: '--my-font',
})
const myFont1Override = localFont({
  src: '../fonts/my-font.woff2',
  declarations: [
    {
      prop: 'font-family',
      value: 'foobar',
    },
  ],
})

const roboto = localFont({
  preload: false,
  src: [
    {
      path:

2',
      weight: '400',
      style: 'italic',
    },
    {
      path: '../fonts/roboto/roboto-400.woff2',
      weight: '400',
    },
    {
      path: '../fonts/my-font.woff2',
      style: 'italic',
    },
    {
      path: '../fonts/my-font.woff2',

'../fonts/roboto/roboto-100-italic.woff2',
      weight: '100',
      style: 'italic',
    },
    {
      path: '../fonts/my-font.woff2',
      weight: '100',
      style: 'normal',
    },
    {
      path: '../fonts/my-font.woff


retry } from 'next-test-utils'

const customErrNo404Match =
  /You have added a custom \/_error page without a custom \/404 page/

describe('Custom _error', () => {
  const { next, isNextDev, isNextStart } = nextTestSetup({
    files: __dirname,
    dependencies: {
      react: '19.3.0-canary-fef12a01-20260413',
      'react-dom': '19.3.0-canary-fef12a01-20260413',
    },
    skipDeployment: true,
  })

  if (isNextDev) {
    it('should not warn with /_error and /404 when rendering error first', async () =>

html).toContain("Expected '\\u003c/', got '\\u003ceof\\u003e'")
          expect(next.cliOutput.slice(outputIndex)).not.toMatch(
            customErrNo404Match
          )
        })
      } finally {
        await next.deleteFile('pages/404.js')
      }

 {
      const outputIndex = next.cliOutput.length
      await next.patchFile('pages/404.js', 'export default <h1>')
      try {
        await retry(async () => {
          const html = await next.render('/404')
          expect(


are Redirect', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(join(__dirname, '../app/pages')),
      ...(process.env.TEST_NODE_MIDDLEWARE
        ? {
            'proxy.js': new FileRef(join(__dirname, '../app/middleware.js')),
          }
        : {
            'middleware.js': new FileRef(
              join(__dirname, '../app/middleware.js')
            ),
          }),
      'next.config.js': new FileRef(join(__dirname, '../app/next.config.js')),
    },
  })
  functio

rElementByCss('#dynamic')
      expect(await browser.elementByCss('#dynamic').text()).toBe(
        'Welcome to a /dynamic/[slug]: new'
      )
    })

    it('does not include the locale in redirects by default', async () => {
      const res = await fetc

n tests() {
    it('should redirect correctly with redirect in next.config.js', async () => {
      const browser = await next.browser('/')
      await browser.eval('window.next.router.push("/to-new")')
      await browser.waitFo


default async function middleware(request) {
  const url = request.nextUrl

  // this is needed for tests to get the BUILD_ID
  if (url.pathname.startsWith('/_next/static/__BUILD_ID')) {
    return NextResponse.next()
  }

  if (url.pathname === '/old-home') {
    if (url.searchParams.get('override') === 'external') {
      return Response.redirect('https://example.vercel.sh')
    } else {
      url.pathname = '/new-home'
      return Response.redirect(url)
    }
  }

  if (url.searchParams.get('foo') === '

turn Response.redirect(url)
  }

  if (url.pathname === '/redirect-me-alot-2') {
    url.pathname = '/redirect-me-alot-3'
    return Response.redirect(url)
  }

  if (url.pathname === '/redirect-me-alot-3') {
    url.pathname = '/redirect-me-alot-4'
    re

bar') {
    url.pathname = '/new-home'
    url.searchParams.delete('foo')
    return Response.redirect(url)
  }

  // Chained redirects
  if (url.pathname === '/redirect-me-alot') {
    url.pathname = '/redirect-me-alot-2'
    re


from 'next/link'

export default function Home() {
  return (

Home Page

      <Link href="/old-home" id="old-home">
        Redirect me to a new version of a page
      </Link>

      <Link href="/old-home?override=external" id="old-home-external">
        Redirect me to an external site
      </Link>

      <Link href="/blank-page?foo=bar">Redirect me with URL params intact</Link>

      <Link href="/redirect-to-google">

e-alot">Redirect me alot (chained requests)</Link>

      <Link href="/infinite-loop">Redirect me alot (infinite loop)</Link>

      <Link
        href="/to?pathname=/api/ok"
        locale="nl"
        id="link-to-api-with-locale

Redirect me to Google (with no body response)
      </Link>

      <Link href="/redirect-to-google">
        Redirect me to Google (with no stream response)
      </Link>

      <Link href="/redirect-m


tTestSetup } from 'e2e-utils'

describe('transpile-packages-typescript-foreign', () => {
  describe('without transpilePackages', () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      skipDeployment: true,
      skipStart: true,
      dependencies: {
        pkg: `file:./pkg`,
      },
    })

    if (skipped) {
      return
    }

    it('should fail', async () => {
      try {
        await next.start()
        await next.render('/')
      } catch (e) {}

      if (process.env

).toBeLessThanOrEqual(1)
        expect(next.cliOutput.match(/Missing module type/g)?.length ?? 0).toBe(
          0
        )
      } else {
        expect(next.cliOutput).toContain(`pkg/index.ts
Module parse failed: Unexpected token`)
      }
    })
  })

.IS_TURBOPACK_TEST) {
        expect(next.cliOutput).toContain(`pkg/index.ts
Unknown module type
This module doesn't have an associated type`)
        expect(
          next.cliOutput.match(/Unknown module type/g).length


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

describe('nested index.js', () => {
  const { next, isTurbopack, skipped } = nextTestSetup({
    files: __dirname,
    // Vercel's deploy infrastructure normalizes nested `/index/index/index`
    // paths differently from Next.js's local server, so the routing
    // assertions here are local-only.
    skipDeployment: true,
  })
  if (skipped) return

  it('should ssr page /', async () => {
    const $ = await next.render$('/')
    expect($('#page').text()).toBe('index

', async () => {
    const browser = await next.browser('/links')
    await browser.elementByCss('#link1').click()
    await retry(async () => {
      const text = await browser.elementByCss('#page').text()
      expect(text).toBe('index')
    })
  })

  i

')
  })

  it('should client render page /', async () => {
    const browser = await next.browser('/')
    const text = await browser.elementByCss('#page').text()
    expect(text).toBe('index')
  })

  it('should follow link to /


ame,
  })

  describe('_document', () => {
    it('should include required elements in rendered html', async () => {
      const $ = await next.render$('/')
      // It has a custom html class
      expect($('html').hasClass('test-html-props')).toBe(true)
      // It has a custom body class
      expect($('body').hasClass('custom_class')).toBe(true)
      // It injects custom head tags
      expect($('head').text()).toMatch('body { margin: 0 }')
      // It has __NEXT_DATA__ script tag
      expect($('scrip

senting app shell', async () => {
      // Extract css-in-js-class from the rendered HTML, which is returned by Document.getInitialProps
      const $index = await next.render$('/')
      const $about = await next.render$('/about')
      expect($index('#cs

t#__NEXT_DATA__')).toBeTruthy()
      // It passes props from Document.getInitialProps to Document
      expect($('#custom-property').text()).toBe('Hello Document')
    })

    it('Document.getInitialProps returns html prop repre


mport App from 'next/app'
import React from 'react'
import { setState } from '../shared-module'

setState(typeof window === 'undefined' ? 'UPDATED' : 'UPDATED CLIENT')

class Layout extends React.Component {
  state = {
    random: false,
  }

  componentDidMount() {
    this.setState({ random: Math.random() })
  }

  render() {
    const { children } = this.props
    const { random } = this.state
    return (

Hello App

Hello HMR

ops = {}

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }

    return { pageProps }
  }

  render() {
    const { Component, pageProps } = this.props
    return (
      <Layout>
        <Component {...pageP

{random}

        {children}

    )
  }
}

export default class MyApp extends App {
  static async getInitialProps({ Component, router, ctx }) {
    // throw _app GIP err here
    let pagePr


, Head, Main, NextScript } from 'next/document'

const cspHashOf = (text) => {
  const hash = crypto.createHash('sha256')
  hash.update(text)
  return `'sha256-${hash.digest('base64')}'`
}

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    let options

    const enhanceComponent = (Component) => (props) => (

        RENDERED
        <Component {...props} />

    )
    const enhanceApp = (Compon

x.query.withEnhanceComponent || ctx.query.withEnhanceApp) {
      options = {}
      if (ctx.query.withEnhanceComponent) {
        options.enhanceComponent = enhanceComponent
      }
      if (ctx.query.withEnhanceApp) {
        options.enhanceApp = enhanc

ent) => (props) => (

        RENDERED
        <Component {...props} />

    )

    if (ctx.query.withEnhancer) {
      options = enhanceComponent
    } else if (ct


ic from 'next/dynamic'
import { useState, useEffect } from '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.joi

')
  const [beforeHydration, setBeforeHydration] = useState(
    'the-second-server-value'
  )
  useEffect(() => {
    setFirstRender(document.getElementById('foo').innerHTML)
    setBeforeHydration(BEFORE_HYDRATION)
  }, [])

  return (
    <>
      <div

n(' ')
    origError(...args)
  }
}

const BEFORE_HYDRATION =
  typeof document !== 'undefined' && document.getElementById('foo').innerHTML

const Index = () => {
  const [firstRender, setFirstRender] = useState('the-server-value


import { renderViaHTTP } from 'next-test-utils'
import cheerio from 'cheerio'
import path from 'path'

async function matchLogs(browser, includes: string) {
  let found = false

  const browserLogs = await browser.log()

  browserLogs.forEach((log) => {
    if (log.message.includes(includes)) {
      found = true
    }
  })
  return found
}

const appDir = path.join(__dirname, 'app')

describe('New Link Behavior', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(path.join(app

  const $ = cheerio.load(html)
    const $a = $('a')
    expect($a.text()).toBe('About')
    expect($a.attr('href')).toBe('/about')
  })

  it('should navigate to /about', async () => {
    const browser = await next.browser(`/`)
    await browser.elementB

Dir, 'pages')),
      'next.config.js': new FileRef(path.join(appDir, 'next.config.js')),
    },
    dependencies: {},
  })

  it('should render link with <a>', async () => {
    const html = await renderViaHTTP(next.url, '/')


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

const appDir = path.join(__dirname, 'material-ui')

describe('New Link Behavior with material-ui', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(path.join(appDir, 'pages')),
      src: new FileRef(path.join(appDir, 'src')),
      'next.config.js': new FileRef(path.join(appDir, 'next.config.js')),
    },
    dependencies: {
      '@emotion/cache': 'latest',
      '@emotion/react': 'latest',
      '@e

    const browser = await next.browser(`/`)
    const element = browser.elementByCss('a[href="/about"]')

    const color = await element.getComputedCss('color')
    expect(color).toBe('rgb(25, 133, 123)')

    const text = await element.text()
    expect(

motion/server': 'latest',
      '@emotion/styled': 'latest',
      '@mui/icons-material': 'latest',
      '@mui/material': 'latest',
      'prop-types': 'latest',
    },
  })

  it('should render MuiLink with <a>', async () => {


hemeProvider } from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
import { CacheProvider } from '@emotion/react'
import theme from '../src/theme'
import createEmotionCache from '../src/createEmotionCache'

// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache()

export default function MyApp(props) {
  const { Component, emotionCache = clientSideEmotionCache, pageProps } = props

  return (
    <CacheProv

a name="viewport" content="initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
        <CssBaseline />
        <Component

ider value={emotionCache}>
      <Head>
        <met


.config'
import StitchesLogo from '../components/StitchesLogo'

const Box = styled('div', {})

const Text = styled('p', {
  fontFamily: '$system',
  color: '$hiContrast',
})

const Link = styled('a', {
  fontFamily: '$system',
  textDecoration: 'none',
  color: '$purple600',
})

const Container = styled('div', {
  marginX: 'auto',
  paddingX: '$3',

  variants: {
    size: {
      1: {
        maxWidth: '300px',
      },
      2: {
        maxWidth: '585px',
      },
      3: {
        maxWidth: '865px',

) {
  return (
    <Box css={{ paddingY: '$6' }}>
      <Container size={{ '@initial': '1', '@bp1': '2' }}>
        <StitchesLogo />
        <Text as="h1">Hello, from About.</Text>
        <Text>
          <Link href="/">Visit Home</Link>.
        </Text>

    },
    },
  },
})

export default function Home(


go from '../components/StitchesLogo'

const Box = styled('div', {})

const Text = styled('p', {
  fontFamily: '$system',
  color: '$hiContrast',
})

const Link = styled(NextLink, {
  fontFamily: '$system',
  textDecoration: 'none',
  color: '$purple600',
})

const Container = styled('div', {
  marginX: 'auto',
  paddingX: '$3',

  variants: {
    size: {
      1: {
        maxWidth: '300px',
      },
      2: {
        maxWidth: '585px',
      },
      3: {
        maxWidth: '865px',
      },
    },
  },
})

ox css={{ paddingY: '$6' }}>
      <Container size={{ '@initial': '1', '@bp1': '2' }}>
        <StitchesLogo />
        <Text as="h1">Hello, from Stitches.</Text>
        <Text>
          <Link href="/about">Visit About</Link>.
        </Text>
      </Cont

export default function Home() {
  return (
    <B


pped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  afterEach(async () => {
    await next.deleteFile('middleware.js').catch(() => {})
    await next.stop().catch(() => {})
  })

  function writeMiddleware(matchers: any) {
    return next.patchFile(
      'middleware.js',
      `
      import { NextResponse } from 'next/server'

      export default function middleware() {
        return NextResponse.next()
      }

      export const c

 (isTurbopack && !isDev) {
      expect(stderr).toContain('Turbopack build failed with 10 errors')

      let matches = 0
      matches += stderr.includes('Missing `source` in `matcher[0]` object')
        ? 1
        : 0
      matches += stderr.includes('

onfig = {
        matcher: ${JSON.stringify(matchers)},
      }
    `
    )
  }

  /** Same branching as integration `runTests(getStderr, isDev)`. */
  function assertInvalidMatchersStderr(stderr: string, isDev: boolean) {
    if


in(__dirname, '../app/node_modules/shared-package')
        ),
      },
      nextConfig: {
        experimental: {
          webpackBuildWorker: true,
        },
        ...(i18n
          ? {
              i18n: {
                locales: ['en', 'fr', 'nl'],
                defaultLocale: 'en',
              },
            }
          : {}),
        async redirects() {
          return [
            {
              source: '/redirect-1',
              destination: '/somewhere/else',
              permanen

          source: '/rewrite-2',
              destination: '/about/a?from=next-config',
            },
            {
              source: '/sha',
              destination: '/shallow',
            },
            {
              source: '/rewrite-3',

t: false,
            },
          ]
        },
        async rewrites() {
          return [
            {
              source: '/rewrite-1',
              destination: '/ssr-page?from=config',
            },
            {


export default function Shallow({ message }) {
  const { pathname, query } = useRouter()
  return (

{message}

          <Link href="/sha?hello=world" shallow id="shallow-link">
            Shallow link to ?hello=world
          </Link>

          <Link href="/sha?hello=goodbye" id="deep-link">
            Deep link to ?hello=goodbye
          </Link>

            Current query: {JSON.stringify(query)}

  )
}

let i = 0

export const getServerSideP


ort { useRouter } from 'next/router'
import { useEffect } from 'react'
import { useState } from 'react'

export default function Page(props) {
  const router = useRouter()
  const [asPath, setAsPath] = useState(
    router.isReady ? router.asPath : router.href
  )

  if (!props.params) {
    console.error('props', props)
    throw new Error('missing props!!!')
  }

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

  return (
    <>

export function getStaticProps({ params }) {
  if (params.slug.includes('not-found')) {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      now: Date.now(),
      params,
    },
  }
}

export function getStaticPaths() {
  return {

/blog/[slug]

{JSON.stringify(router.query)}

{router.pathname}

{asPath}

{JSON.stringify(props)}

    </>
  )
}


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

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

  describe('with middleware', () => {
    it('should not trigger unnecessary rerenders when middleware is used', async () => {
      const browser = await next.browser('/')

      await retry(async () => {
        const renders = await browser.eval('window.__renders')
        expect(renders).toEqual([undefined])
      })
    })
  })

  describe('with r

> {
    // TODO: Figure out the `isReady` issue.
    it.skip('should not trigger unnecessary rerenders when rewrites are used', async () => {})
    it.skip('should rerender with the correct query parameter if present with rewrites', async () => {})
  })
})


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

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

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

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

    let time

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

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

  const menuRef = useRef(null)

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

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

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


v } from 'e2e-utils'

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

  describe('bundle pages externals with config.bundlePagesRouterDependencies', () => {
    if (!isNextStart) {
      it('skip for non-production mode', () => {})
      return
    }

    beforeAll(async () => {
      await next.build()
    })

    it('should have no externals with the config s

        expect(pageBundleBasenames).not.toBeEmpty()
        let allBundles = ''
        for (const basename of pageBundleBasenames) {
          const output = await fs.readFile(join(ssrPath, basename), 'utf8')
          allBundles += output
        }

et', async () => {
      if (isTurbopack) {
        const ssrPath = join(next.testDir, '.next/server/chunks/ssr')
        const pageBundleBasenames = (await fs.readdir(ssrPath)).filter((p) =>
          p.match(/\.js$/)
        )


eRef, isNextDev, nextTestSetup } from 'e2e-utils'
import path from 'path'

const appDir = path.join(__dirname, 'child-a-tag-error')

describe('New Link Behavior with <a> child', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(path.join(appDir, 'pages')),
      'next.config.js': new FileRef(path.join(appDir, 'next.config.js')),
    },
    dependencies: {
      next: 'latest',
    },
  })

  it('should throw error with <a> child', async () => {
    const browser = await next.b

or>'
      )
      await expect(browser).toDisplayRedbox(`
       {
         "code": "E209",
         "description": "Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavior>.
       Learn more: https://nextjs.org/docs/messages/invalid

rowser(`/`)
    const link = await browser.elementsByCss('a[href="/about"]')

    if (isNextDev) {
      expect(next.cliOutput).toContain(
        'Error: Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavi


ath'

const appDir = path.join(__dirname, 'stitches')

describe('New Link Behavior with stitches', () => {
  const { next } = nextTestSetup({
    files: {
      pages: new FileRef(path.join(appDir, 'pages')),
      components: new FileRef(path.join(appDir, 'components')),
      'next.config.js': new FileRef(path.join(appDir, 'next.config.js')),
      'stitches.config.js': new FileRef(
        path.join(appDir, 'stitches.config.js')
      ),
    },
    dependencies: {
      '@stitches/react': '^1.2.6',

>', async () => {
    const browser = await next.browser(`/`)
    const element = await browser.elementByCss('a[href="/about"]')

    const color = await element.getComputedCss('color')
    expect(color).toBe('rgb(78, 39, 231)')

    const text = await ele

 next: 'latest',
    },
  })

  it('should render <a


StitchesLogo = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="35"
    height="35"
    viewBox="0 0 35 35"
    fill="none"
  >
    <circle
      cx="17.5"
      cy="17.5"
      r="14.5"
      stroke="currentColor"
      strokeWidth="2"
    />
    <path d="M12.8184 31.3218L31.8709 20.3218" stroke="currentColor" />
    <path d="M3.31836 14.8674L22.3709 3.86743" stroke="currentColor" />
    <path
      d="M8.65332 29.1077L25.9738 19.1077"
      stroke="currentColor"
      strokeLinecap="round"

lor"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path
      d="M16.6973 12.2302L25.9736 19.1078"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path
      d="M9.21582 16.0815L19.045

      strokeLinejoin="round"
    />
    <path
      d="M9.21582 16.0815L26.5363 6.08154"
      stroke="currentColor"
      strokeLinecap="round"
    />
    <path
      d="M13.2334 14.2297L22.5099 21.1077"
      stroke="currentCo


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

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

  it('Supports commonjs 1', async () => {
    const browser = await next.browser('/commonjs1')
    const html = await browser.eval('document.body.innerHTML')
    expect(html).toMatch(/test1/)
    expect(html).toMatch(/nextExport/)
  })

  it('Supports commonjs 2', async () => {
    const browser = await next.browser('/commonjs2')
    const html =

ait retry(async () => {
      const html = await browser.eval('document.body.innerHTML')
      expect(html).toMatch(/post.*post-1/)
    })
    const html = await browser.eval('document.body.innerHTML')
    expect(html).toMatch(/nextExport/)
  })

  it('sho

 await browser.eval('document.body.innerHTML')
    expect(html).toMatch(/test2/)
    expect(html).toMatch(/nextExport/)
  })

  it('Refreshes query on mount', async () => {
    const browser = await next.browser('/post-1')
    aw


 regions: 'auto',
}

const PATTERNS = [
  [
    new URLPattern({ pathname: '/:locale/:id' }),
    ({ pathname }) => ({
      pathname: '/:locale/:id',
      params: pathname.groups,
    }),
  ],
  [
    new URLPattern({ pathname: '/:id' }),
    ({ pathname }) => ({
      pathname: '/:id',
      params: pathname.groups,
    }),
  ],
]

const params = (url) => {
  const input = url.split('?')[0]
  let result = {}

  for (const [pattern, handler] of PATTERNS) {
    const patternResult = pattern.exec(input)

rl

  if (request.headers.get('x-prerender-revalidate')) {
    return NextResponse.next({
      headers: { 'x-middleware': 'hi' },
    })
  }

  // this is needed for tests to get the BUILD_ID
  if (url.pathname.startsWith('/_next/static/__BUILD_ID')) {

 if (patternResult !== null && 'pathname' in patternResult) {
      result = handler(patternResult)
      break
    }
  }
  return result
}

export async function middleware(request) {
  getSomeData()

  const url = request.nextU


xtTestSetup } from 'e2e-utils'

describe('Document and App - Client side', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  it('should share module state with pages', async () => {
    const browser = await next.browser('/shared')

    const text = await browser.elementByCss('#currentstate').text()
    expect(text).toBe('UPDATED CLIENT')
  })

  if (isNextDev) {
    it('should detect the changes to pages/_app.js and display it', async () => {

 expect(text).toBe('Hello HMR')

        // change the content
        const editedContent = originalContent.replace('Hello HMR', 'Hi HMR')
        await next.patchFile(appPath, editedContent)

        await retry(async () =>
          expect(await browser

  const appPath = 'pages/_app.js'
      const originalContent = await next.readFile(appPath)
      try {
        const browser = await next.browser('/')
        const text = await browser.elementByCss('#hello-hmr').text()


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

// This test relies on an experimental webpack feature (lazyCompilation).
describe('next/dynamic lazy compilation', () => {
  if (shouldUseTurbopack()) {
    it('skips in Turbopack tests', () => {})
    return
  }

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

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

).toMatch(/the-second-server-value/i)
  })

  it('should render dynamic server rendered values before hydration', async () => {
    const browser = await next.browser('/')
    const text = await browser.elementByCss('#before-hydr


tml, Head, Main, NextScript } from 'next/document'
import createEmotionServer from '@emotion/server/create-instance'
import theme from '../src/theme'
import createEmotionCache from '../src/createEmotionCache'

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          {/* PWA primary color */}
          <meta name="theme-color" content={theme.palette.primary.main} />
          <link rel="shortcut icon" href="/static/favicon.ico" />

/}
          {this.props.emotionStyleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with static

<link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
          />
          {/* Inject MUI styles first to match with the prepend: true configuration. *


lue from 'shared-package'

export const config = {
  regions: 'auto',
  runtime: 'nodejs',
}

// When there is a top level await, requiring middleware.js will return a Promise
await new Promise((resolve) => {
  setTimeout(resolve, 100)
})

const PATTERNS = []

const params = (url) => {
  const input = url.split('?')[0]
  let result = {}

  for (const [pattern, handler] of PATTERNS) {
    const patternResult = pattern.exec(input)
    if (patternResult !== null && 'pathname' in patternResult) {
      result =

th.join(process.cwd(), 'package.json')
    // @vercel/nft's static analysis only recognizes the callback `fs.readFile`
    // (and `readFileSync` etc.), not `fs.promises.readFile`. Using the
    // callback form lets NFT resolve the path argument and inclu

 handler(patternResult)
      break
    }
  }
  return result
}

export async function middleware(request) {
  getSomeData()

  const url = request.nextUrl

  if (url.pathname.startsWith('/test-node-fs')) {
    const pkgPath = pa


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

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

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

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

    statusRe

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

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

  useEffect(() => {
    const timeout = setTimeout(
      () => {
        flushSync(() => {
          setIsVisible(fal


t.secondary">
      <LightBulbIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
      Pro tip: See more{' '}
      <Link href="https://mui.com/getting-started/templates/">
        templates
      </Link>{' '}
      on the MUI documentation.
    </Typography>

n (
    <Typography sx={{ mt: 6, mb: 3 }} color="tex


 { nextTestSetup } from 'e2e-utils'

describe('styled-jsx dynamic styles SSR', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  // Dynamic styled-jsx (with interpolated expressions) produces numeric class
  // names at runtime via the DJB2 hash in styled-jsx's computeId function.
  // This pattern matches production deployments where all jsx class names
  // are numeric (e.g. jsx-2267428885) rather than hex (jsx-f36313d9f07883b7).
  it('should contain dynami

('Numeric jsx classes:', [...new Set(numericClasses)])
    expect(numericClasses.length).toBeGreaterThan(0)

    // All dynamic styles should be present as inline <style> tags
    expect(html).toMatch(/color:.*?green/) // main page
    expect(html).toMatch

c styled-jsx styles during SSR', async () => {
    const html = await next.render('/')

    // Dynamic styled-jsx produces numeric class names at runtime
    const numericClasses = html.match(/\bjsx-\d+\b/g) || []
    console.log


ort { nextTestSetup } from 'e2e-utils'

describe('children-page', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  describe('with app dir', () => {
    it('should show the content if you have a page named children', async () => {
      const browser = await next.browser('/children')

      const text = await browser.waitForElementByCss('#children-page').text()

      expect(text).toBe('children - app')

      const currentDisplay = await browser.eval(
        `window.getComputedStyle

   const browser = await next.browser('/other/children')

      const text = await browser.waitForElementByCss('#children-page').text()

      expect(text).toBe('children - pages')

      const currentDisplay = await browser.eval(
        `window.getComput

(document.querySelector('body')).display`
      )

      expect(currentDisplay).toBe('block')
    })
  })

  describe('with pages dir', () => {
    it('should show the content if you have a page named children', async () => {


rt, nextTestSetup } from 'e2e-utils'

let proxyPort: number

const runTests = (
  next: ReturnType<typeof nextTestSetup>['next'],
  switchDeployment: (bool) => void
) => {
  it('index to gsp', async () => {
    switchDeployment(false)
    const browser = await next.browser('/', { baseUrl: proxyPort })

    await browser.eval('window.beforeNav = 1')
    await browser.waitForElementByCss('#index')

    switchDeployment(true)

    await browser.eval(`(function() {
      window.next.router.push('/gsp')
    })()

 baseUrl: proxyPort })

    await browser.eval('window.beforeNav = 1')
    await browser.waitForElementByCss('#gsp')

    switchDeployment(true)

    await browser.eval(`(function() {
      window.next.router.push('/gssp')
    })()`)
    await browser.wait

`)
    await browser.waitForElementByCss('#gsp')

    expect(await browser.eval('window.beforeNav')).toBeFalsy()
  })

  it('gsp to gssp', async () => {
    switchDeployment(false)
    const browser = await next.browser('/gsp', {


Page(props) {
  const router = useRouter()

  return (
    <>

index page

{router.pathname}

{JSON.stringify(router.query)}

      {router.query.imageId ?
show modal
 : null}

      <Link href="/?imageId=123" as="/preview/123" id="to-modal">
        open modal for /preview/123
      </Link>

      <Link href="/preview/123" id="to-preview">
        go to /preview/123
      </Link>

      <Link

her
      </Link>

      <Link href="/rewrite-me" id="to-rewrite-me">
        go to /rewrite-me
      </Link>

      <Link href="/" as="/rewrite-me" id="to-index-as-rewrite">
        go to / as /rewrite-me
      </Link>
      <br

href="/another" id="to-another">
        go to /anot


Router } from 'next/router'
import Link from 'next/link'

export const getStaticProps = ({ params }) => {
  return {
    props: {
      params: params || null,
      preview: true,
    },
  }
}

export const getStaticPaths = () => {
  return {
    paths: [],
    fallback: 'blocking',
  }
}

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

  return (
    <>

preview page

{router.pathname}

{JSON.stringify(router.query)}

w">
        go to /preview/321
      </Link>

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

      <Link href="/rewrite-me" id="to-rewrite-me">
        go to /rewrite-me
      </Link>
      <br

{JSON.stringify(props)}

      <Link href="/?imageId=123" as="/preview/123" id="to-modal">
        open modal for /preview/123
      </Link>

      <Link href="/preview/321" id="to-previe


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

const CASES = [
  [
    'turbopackPersistentCaching',
    "Use 'experimental.turbopackFileSystemCacheForDev' instead.",
  ],
  [
    'turbopackPersistentCachingForDev',
    "Use 'experimental.turbopackFileSystemCacheForDev' instead.",
  ],
  [
    'turbopackPersistentCachingForBuild',
    "Use 'experimental.turbopackFileSystemCacheForBuild' instead.",
  ],
]

describe('persistent-caching-migration', () => {
  for (const [option, error] o

      },
        skipDeployment: true,
        skipStart: true,
      })

      if (skipped) {
        return
      }

      if (!isTurbopack) {
        it.skip('only for turbopack', () => {})
        return
      }

      if (isNextStart) {
        it('er

f CASES) {
    describe(option, () => {
      const { skipped, next, isTurbopack, isNextStart } = nextTestSetup({
        files: {
          'next.config.js': `module.exports = {
  experimental: {
    ${option}: true,
  },
}`,


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

  it('should have gip in __NEXT_DATA__', async () => {
    const $ = await next.render$('/')
    expect(JSON.parse($('#__NEXT_DATA__').text()).gip).toBe(true)
  })

  it('should not have gip in __NEXT_DATA__ for non-GIP page', async

= await next.render$('/blog/1')
    expect($('#as-path').text()).toBe('/blog/1')
  })

  it('should have correct router.asPath for direct visit dynamic page rewrite direct', async () => {
    const $ = await next.render$('/blog/post/1')
    expect($('#as-p

 () => {
    const $ = await next.render$('/normal')
    expect('gip' in JSON.parse($('#__NEXT_DATA__').text())).toBe(false)
  })

  it('should have correct router.asPath for direct visit dynamic page', async () => {
    const $


tripAnsi from 'strip-ansi'

const pagePath = 'pages/index.jsx'
const apiPath = 'pages/api/edge.js'

;(process.env.IS_TURBOPACK_TEST ? describe.skip.each : describe.each)([
  { appDir: join(__dirname, './app/src'), title: 'src/pages and API routes' },
  { appDir: join(__dirname, './app'), title: 'pages and API routes' },
])('Configurable runtime for $title', ({ appDir }) => {
  if (isNextDev) {
    describe('In development mode', () => {
      const { next } = nextTestSetup({
        files: appDir,
        s

)

      afterEach(async () => {
        await next.stop()
        await next.patchFile(pagePath, originalPage)
        await next.patchFile(apiPath, originalApi)
      })

      it('runs with no warning API route on the edge runtime', async () => {

kipStart: true,
      })

      let originalPage: string
      let originalApi: string

      beforeAll(async () => {
        originalPage = await next.readFile(pagePath)
        originalApi = await next.readFile(apiPath)
      }


retry } from 'next-test-utils'

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

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

  it('isReady should be true immediately for getInitialProps page', async () => {
    const bro

=world')
    await checkIsReadyValues(browser, [true])
  })

  it('isReady should be true immediately for getServerSideProps page', async () => {
    const browser = await next.browser('/gssp')
    await checkIsReadyValues(browser, [true])
  })

  it('isRe

wser = await next.browser('/gip')
    await checkIsReadyValues(browser, [true])
  })

  it('isReady should be true immediately for getInitialProps page with query', async () => {
    const browser = await next.browser('/gip?hello


from 'e2e-utils'

describe('API body parser', () => {
  describe('without custom server', () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      // Uses a custom HTTP/proxy server in front of Next.js; not applicable in deploy mode.
      skipDeployment: true,
    })
    if (skipped) return

    it('should parse JSON body', async () => {
      const res = await next.fetch('/api', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json; charset=utf

) => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
      startCommand: 'node server.js',
      serverReadyPattern: /- Local:/,
      env: { CUSTOM_SERVER: 'true' },
      dependencies: {
        express: '4',
      },
      // Use

-8',
        },
        body: JSON.stringify([{ title: 'Nextjs' }]),
      })
      const data = await res.json()
      expect(data).toEqual([{ title: 'Nextjs' }])
    })
  })

  describe('with custom server (pre-parsed body)', (


 } from 'next-test-utils'

describe('manual-client-base-path', () => {
  if ((global as any).isNextDeploy) {
    it('should skip deploy', () => {})
    return
  }

  let server: http.Server
  let appPort: string
  const basePath = '/docs-proxy'
  const responses = new Set()

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

  beforeAll(async ()

r IPv6 over IPv4
      destination.hostname = '127.0.0.1'

      if (req.url.startsWith(basePath)) {
        destination.pathname = reqUrl.pathname || '/'
      } else {
        destination.pathname = `${basePath}${
          reqUrl.pathname === '/' ? '' :

=> {
    const getProxyTarget = (req) => {
      const destination = new URL(next.url)
      const reqUrl = new URL(req.url, 'http://localhost')
      // force IPv4 for testing in node 17+ as the default
      // switched to favo


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

export default function Page(props) {
  const router = useRouter()
  const [mounted, setMounted] = useState(false)

  useEffect(() => {
    setMounted(true)
  }, [])

  return (
    <>

another page

{JSON.stringify(props)}

        {JSON.stringify(
          mounted
            ? {
                basePath: router.basePath,

</Link>

      <Link href="/dynamic/first" id="to-dynamic">
        to /dynamic/first
      </Link>

    </>
  )
}

export function getServerSideProps() {
  return {
    props: {
      hello: 'world',
      now: Date.now(),
    },

           pathname: router.pathname,
                asPath: router.asPath,
                query: router.query,
              }
            : {}
        )}
      </p>

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


mport { useEffect, useState } from 'react'

export default function Page(props) {
  const router = useRouter()
  const [mounted, setMounted] = useState(false)

  useEffect(() => {
    setMounted(true)
  }, [])

  return (
    <>

index page

{JSON.stringify(props)}

        {JSON.stringify(
          mounted
            ? {
                basePath: router.basePath,
                pathname: router.pathname,
                asPath: router.asP

}
            : {}
        )}

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

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

      <Link href=

ath,
                query: router.query,


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

export default function Page(props) {
  const router = useRouter()
  const [mounted, setMounted] = useState(false)

  useEffect(() => {
    setMounted(true)
  }, [])

  return (
    <>

dynamic page

{JSON.stringify(props)}

        {JSON.stringify(
          mounted
            ? {
                basePath: router.basePath,

k>

      <Link href="/dynamic/second" id="to-dynamic">
        to /dynamic/second
      </Link>

    </>
  )
}

export function getStaticPaths() {
  return {
    paths: ['/dynamic/first'],
    fallback: true,
  }
}

export functio

     pathname: router.pathname,
                asPath: router.asPath,
                query: router.query,
              }
            : {}
        )}
      </p>

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


 normalize(str: string) {
  return str.replace(/<!-- -->/g, '')
}

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

  // Pages
  describe.each(['/static', '/ssr', '/ssg'])('pages url %s', (url) => {
    // For invalid esm packages that have "import" pointing to a non-esm-flagged module
    // webpack is using the CJS version instead, but Turbopack is opting out of
    // externalizing and bundling the non-esm-flagged module.
    const expectedHtml

 the client side, webpack always bundles, so it uses the non-esm-flagged module too.
    const expectedText =
      isTurbopack || url === '/static'
        ? 'Hello World+World+World+World+World+World'
        : 'Hello World+World+World+World+World+Altern

 = isTurbopack
      ? 'Hello World+World+World+World+World+World'
      : url === '/static'
        ? 'Hello World+World+Alternative+World+World+World'
        : 'Hello World+World+Alternative+World+World+Alternative'

    // On


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

// Tests Babel, not needed for Turbopack
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'swc warnings by default',
  () => {
    const { next } = nextTestSetup({
      files: {
        'pages/index.js': `
          export default function Page() {
            return
hello world

          }
        `,
        '.babelrc': `
          {
            "presets": ["next/babel"]
          }
        `,
      },
      dependenc

     )
    })
  }
)

// Tests Babel, not needed for Turbopack
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'can force swc',
  () => {
    const { next } = nextTestSetup({
      nextConfig: {
        experimental: {
          forceSwcTrans

ies: {},
    })

    it('should have warning', async () => {
      await renderViaHTTP(next.url, '/')
      expect(next.cliOutput).toContain(
        'Disabled SWC as replacement for Babel because of custom Babel configuration'


port { nextTestSetup } from 'e2e-utils'

describe('api-resolver-query-writeable', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    startCommand: 'node server.js',
    serverReadyPattern: /Next mode: (production|development)/,
    dependencies: {
      'get-port': '5.1.1',
      express: '5.1.0',
    },
  })

  if (skipped) {
    return
  }

  it('should allow req.query to be writable and reflect changes made in the API handler', async () => {
    const

ders: {
        'Content-Type': 'application/json; charset=utf-8',
      },
    })
    if (!res.ok) {
      throw new Error('Fetch failed')
    }
    const data = await res.json()
    expect(data).toEqual({ query: { hello: 'yes', changed: 'yes' } })
  })
}

res = await next.fetch('/api?hello=yes', {
      hea


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

describe('i18n-data-fetching-redirect', () => {
  // TODO: investigate tests failures on deploy
  if ((global as any).isNextDeploy) {
    it('should skip temporarily', () => {})
    return
  }

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

  describe('Redirect to locale fro

edirect'} | ${'sv'}
      ${'gsp-fallback-redirect'} | ${'en'}
      ${'gsp-fallback-redirect'} | ${'sv'}
    `('$path $locale', async ({ path, locale }) => {
      const browser = await next.browser(`/${locale}/${path}/from-ctx`)

      await check(

m context', () => {
    test.each`
      path                       | locale
      ${'gssp-redirect'}         | ${'en'}
      ${'gssp-redirect'}         | ${'sv'}
      ${'gsp-blocking-redirect'} | ${'en'}
      ${'gsp-blocking-r


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

describe('i18n-data-fetching-redirect', () => {
  // TODO: investigate tests failures on deploy
  if ((global as any).isNextDeploy) {
    it('should skip temporarily', () => {})
    return
  }

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

  describe('Redirect to another lo

'} | ${'en'}    | ${'sv'}
      ${'gsp-blocking-redirect'} | ${'sv'}    | ${'en'}
      ${'gsp-fallback-redirect'} | ${'en'}    | ${'sv'}
      ${'gsp-fallback-redirect'} | ${'sv'}    | ${'en'}
    `(
      '$path $fromLocale -> $toLocale',
      async ({

cale', () => {
    test.each`
      path                       | fromLocale | toLocale
      ${'gssp-redirect'}         | ${'en'}    | ${'sv'}
      ${'gssp-redirect'}         | ${'sv'}    | ${'en'}
      ${'gsp-blocking-redirect


from 'next/link'

export default function Component() {
  return (
    <>
      <Link href="/gssp-redirect/en" id="to-gssp-redirect-en">
        to /gssp-redirect/en"
      </Link>
      <Link href="/gssp-redirect/sv" id="to-gssp-redirect-sv">
        to /gssp-redirect/sv"
      </Link>
      <Link href="/gssp-redirect/from-ctx" id="to-gssp-redirect-from-ctx">
        to /gssp-redirect/from-ctx
      </Link>

      <Link href="/gsp-blocking-redirect/en" id="to-gsp-blocking-redirect-en">
        to /gsp-bloc

 id="to-gsp-blocking-redirect-from-ctx"
      >
        to /gsp-blocking-redirect/from-ctx
      </Link>

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

king-redirect/en"
      </Link>
      <Link href="/gsp-blocking-redirect/sv" id="to-gsp-blocking-redirect-sv">
        to /gsp-blocking-redirect/sv"
      </Link>
      <Link
        href="/gsp-blocking-redirect/from-ctx"


eslint-disable jest/no-standalone-expect */

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

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

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

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

  // FIXME
  // See https://linear.app/vercel/issue/EC-170

 {
      const res = await fetchViaHTTP(next.url, path)
      expect(res.status).toBe(200)
      expect(res.headers.get('x-from-middleware')).toBeDefined()
    }
  })

  it.each(['/default', '/invalid/base/default'])(
    'should not match',
    async (pat

/middleware-rewrite-of-nextjs-with-basepath-does-not-work-on-vercel
  itif(!isModeDeploy)('should match', async () => {
    for (const path of [
      '/base/default',
      `/base/_next/data/${next.buildId}/default.json`,
    ])


sNextStart } from 'e2e-utils'

describe('404 Page Support with _app', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

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

  if (isNextStart) {
    it('should build successfully', async () => {
      expect(next.cliOutput).toContain('Compiled successfully')
      expect(next.cliOutput).not.toMatch(gip404Err)
      expect(next.cliOutput).not.toContain('Build error occurred')
    })

    it('should not o

  })

    it('specify to use the 404 page still in the routes-manifest', async () => {
      const manifest = await next.readJSON('.next/routes-manifest.json')
      expect(manifest.pages404).toBe(true)
    })
  }

  it('should still use 404 page', async (

utput static 404 if _app has getInitialProps', async () => {
      const browser = await next.browser('/404')
      const isAutoExported = await browser.eval('__NEXT_DATA__.autoExport')
      expect(isAutoExported).toBeFalsy()


les: __dirname,
    skipStart: true,
    skipDeployment: true,
  })
  if (skipped) return

  const gip500Err =
    /`pages\/500` can not have getInitialProps\/getServerSideProps/

  beforeEach(async () => {
    // Reset to original 500.js before each test
    await next.patchFile(
      'pages/500.js',
      `const page = () => {
  console.log('rendered 500')
  return 'custom 500 page'
}
export default page
`
    )
  })

  it('shows error with getInitialProps in pages/500 build', async () => {
    await nex

itCode).toBe(1)
    expect(next.cliOutput).toMatch(gip500Err)
  })

  it('does not show error with getStaticProps in pages/500 build', async () => {
    await next.patchFile(
      'pages/500.js',
      `
      const page = () => 'custom 500 page'
      ex

t.patchFile(
      'pages/500.js',
      `
      const page = () => 'custom 500 page'
      page.getInitialProps = () => ({ a: 'b' })
      export default page
    `
    )
    const { exitCode } = await next.build()
    expect(ex