rentSpan: Span) {
    super.setup(parentSpan)
    await super.createTestDir({ parentSpan })
  }

  public get cliOutput() {
    return this._cliOutput || ''
  }

  private handleStdio = (childProcess) => {
    childProcess.stdout.on('data', (chunk) => {
      const msg = chunk.toString()
      process.stdout.write(chunk)
      this._cliOutput += msg
      this.emit('stdout', [msg])
    })
    childProcess.stderr.on('data', (chunk) => {
      const msg = chunk.toString()
      process.stderr.write(chunk)

t(' ')
    }

    if (this.buildArgs) {
      buildArgs.push(...this.buildArgs)
    }

    if (args) {
      buildArgs.push(...args)
    }

    if (process.env.NEXT_SKIP_ISOLATE) {
      // without isolation yarn can't be used and pnpm must be used instead

   this._cliOutput += msg
      this.emit('stderr', [msg])
    })
  }

  private getBuildArgs(args?: string[]) {
    let buildArgs = ['pnpm', 'next', 'build']

    if (this.buildCommand) {
      buildArgs = this.buildCommand.spli


lient Bundles (main)',
    globs: [
      '.next/static/runtime/+(main|webpack)-*',
      '.next/static/chunks/!(polyfills*)',
    ],
  },
  {
    name: 'Legacy Client Bundles (polyfills)',
    globs: ['.next/static/chunks/+(polyfills)-*'],
  },
  {
    name: 'Client Pages',
    globs: [
      '.next/static/BUILD_ID/pages/!(edge-repeated*)',
      '.next/static/css/**/*',
    ],
  },
  {
    name: 'Client Build Manifests',
    globs: ['.next/static/BUILD_ID/_buildManifest*'],
  },
  {
    name: 'Rendered Pa

: async (nextAppDir, fileName) => {
      if (fileName.startsWith('.next/server/app')) {
        const manifestJson = await fs.readFile(
          path.join(nextAppDir, '.next/server/middleware-manifest.json')
        )
        const manifest = JSON.parse(

ge Sizes',
    globs: ['fetched-pages/!(edge-repeated*)'],
  },
  {
    name: 'Edge SSR bundle Size',
    globs: [
      '.next/server/pages/edge-ssr.js',
      '.next/server/app/app-edge-ssr/page.js',
    ],
    getRequiredFiles


assName="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">

          Get started by editing!!
          app/page.tsx

me="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
            href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
            target="_blank"
            rel="n

     <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
          <a
            classNa


ame="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
            href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
            target="_blank"
            rel="

      <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
          <a
            classN


from 'e2e-utils'
import path from 'path'
import fs from 'fs-extra'

const testedExamples = [
  // Internal features
  'active-class-name',
  'api-routes-cors',
  'api-routes-middleware',
  'api-routes-rest',
  'basic-css',
  'blog',
  'blog-starter',
  'custom-server',
  'hello-world',
  'i18n-routing',
  'i18n-routing-pages',
  'image-component',
  'mdx',
  'next-forms',
  'remove-console',
  'reproduction-template',
  'with-absolute-imports',
  'with-context-api',
  'with-shallow-routing',
  'with-sitemap

describe.each(testedExamples)(`example '%s'`, (example) => {
  // If there is an issue during a build, jest won't tell us which example caused it
  // we need to log it ourselfs
  beforeAll(() => {
    require('console').log(`Running example '${example}'

',
  'with-typescript',
  'with-typescript-types',
  'with-web-worker',
  'with-webassembly',

  // Library integrations that we can't break
  'mdx-pages',
  'mdx-remote',
  'with-jest',
  'with-jest-babel',
  'with-turbopack',
]


quire('fs')
const fsp = require('fs/promises')
const path = require('path')
const { execSync } = require('child_process')

const YELLOW = '\x1b[33m'
const RESET = '\x1b[0m'

/**
 * Check if the Next.js build is fresh (matches current git HEAD).
 * Prints warnings to console if build is missing or stale.
 * @returns {Promise<void>}
 */
async function checkBuildFreshness() {
  const distPath = path.join(__dirname, '../../packages/next/dist')
  const buildCommitPath = path.join(distPath, '.build-commit')

  if

  Run \`pnpm build\` before running tests.\n${RESET}`
    )
    return
  }

  if (!existsSync(buildCommitPath)) {
    console.warn(`${YELLOW}⚠  WARNING: Build may be stale!${RESET}`)
    console.warn(
      `${YELLOW}   Unable to verify build freshness (n

 (!existsSync(distPath)) {
    console.warn(`${YELLOW}⚠  WARNING: No build found!${RESET}`)
    console.warn(
      `${YELLOW}   The packages/next/dist directory does not exist.${RESET}`
    )
    console.warn(
      `${YELLOW}


rom 'fs'
import type { TraceEvent } from 'next/dist/trace'

export interface TraceStructure {
  events: TraceEvent[]
  eventsByName: Map<string, TraceEvent[]>
  eventsById: Map<string, TraceEvent>
  rootEvents: TraceEvent[]
  orphanedEvents: TraceEvent[]
}

/**
 * Parses a Next.js trace file (e.g. `.next/trace` or `.next/trace-build`)
 * and returns the flat list of trace events.
 */
export function parseTraceEvents(tracePath: string): TraceEvent[] {
  const traceContent = readFileSync(tracePath, 'utf8')

 trace file and returns a structured representation
 * with events indexed by name and id, plus root/orphaned classification.
 */
export function parseTraceFile(tracePath: string): TraceStructure {
  const allEvents = parseTraceEvents(tracePath)

  const e

const allEvents: TraceEvent[] = []
  for (const line of traceContent.trim().split('\n')) {
    if (!line.trim()) continue
    allEvents.push(...(JSON.parse(line) as TraceEvent[]))
  }
  return allEvents
}

/**
 * Parses a Next.js


The main use case is for asynchronous e2e tests. It provides a `waitFor`
// method that resolves when the log matches some expected asynchronous sequence
// of events. This is an alternative to setting up a timer loop. It helps catch
// subtle mistakes where the order of events is not expected, or the same
// event happens more than it should.
//
// Based on the Scheduler.log pattern used in the React repo.
export function createTestLog() {
  let events: unknown[] = []

  // Represents a pending waitFor cal

.push(value)

    // Check if we've reached the end of the expected log. If there's a
    // pending waitFor, and we've reached the last of the expected events, this
    // will resolve the promise.
    pingExpectation()
  }

  function assert(expectedEven

l.
  let pendingExpectation: null | {
    resolve: () => void
    reject: (error: Error) => void
    expectedEvents: Array<any>
    error: Error
  } = null

  function log(value: unknown) {
    // Add to the event log.
    events


ache-components-errors/utils'

export type ValidationEvent =
  | { type: 'validation_start'; requestId: string; url: string }
  | { type: 'validation_end'; requestId: string; url: string }

export function parseValidationMessages(output: string): ValidationEvent[] {
  const messageRe = /<VALIDATION_MESSAGE>(.*?)<\/VALIDATION_MESSAGE>/g
  const events: ValidationEvent[] = []
  let match: RegExpExecArray | null
  while ((match = messageRe.exec(output)) !== null) {
    try {
      events.push(JSON.parse(match[

= true } = {}
): string {
  const markerRe = /<VALIDATION_MESSAGE>(.*?)<\/VALIDATION_MESSAGE>/g

  // Find all marker positions and their content
  const markers: {
    index: number
    endIndex: number
    data: ValidationEvent
  }[] = []
  let m: RegExp

1]))
    } catch (err) {
      throw new Error(`Failed to parse message '${match[1]}'`, {
        cause: err,
      })
    }
  }
  return events
}

export function extractBuildValidationError(
  cliOutput: string,
  { isMinified


ortsImmutableAssets: boolean = false
  private _writtenHostsLine: string | null = null

  protected throwIfUnavailable(): void | never {
    if (this.isStopping !== null) {
      throw new Error('Next.js is no longer available.', {
        cause: this.isStopping,
      })
    }
    if (this.isDestroyed !== null) {
      throw new Error('Next.js is no longer available.', {
        cause: this.isDestroyed,
      })
    }
    if (this.childProcess === undefined) {
      // deploy tests don't have access to the

  public get supportsImmutableAssets() {
    return process.env.IS_TURBOPACK_TEST ? this._supportsImmutableAssets : false
  }

  private async deployUsingCustomScript(): Promise<{ url: string }> {
    const deployScriptPath = process.env.NEXT_TEST_DEPLOY_S

 process
    }
  }

  public get buildId() {
    // get deployment ID via fetch since we can't access
    // build artifacts directly
    return this._buildId
  }

  public get deploymentId() {
    return this._deploymentId
  }


ype { Playwright } from './browsers/playwright'
import { NextInstance } from 'e2e-utils'

declare global {
  namespace jest {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars -- module augmentation needs to match generic params even if unused
    interface Matchers<R> {
      /**
       * Inline snapshot matcher for a Redbox that's popped up by default.
       * When a Redbox is hidden at first and requires manual display by clicking the toast,
       * use {@link toDisplayCollapsedRedbox}

intented content in the snapshot should be reported to the Next.js DX team.
       * `<FIXME-internal-frame>` in the snapshot would be unintended.
       * `<FIXME-project-root>` in the snapshot would be unintended.
       * `<FIXME-file-protocol>` in the

instead.
       *
       *
       * If the project root appears in the snapshot, pass in the `NextInstance`
       * as well to normalize the snapshot e.g. `await expect({ browser, next }).toDisplayRedbox()`.
       *
       * Un


 hookPropertyMap = new Map([
  ['react', reactDir],
  ['react/package.json', `${reactDir}/package.json`],
  ['react/jsx-runtime', `${reactDir}/jsx-runtime`],
  ['react/jsx-dev-runtime', `${reactDir}/jsx-dev-runtime`],
  ['react-dom', `${reactDomDir}`],
  ['react-dom/package.json', `${reactDomDir}/package.json`],
  ['react-dom/client', `${reactDomDir}/client`],
  ['react-dom/server', `${reactDomDir}/server`],
  ['react-dom/server.browser', `${reactDomDir}/server.browser`],
  ['react-dom/server.edge', `${reac

mod._resolveFilename
mod._resolveFilename = function (request, parent, isMain, options) {
  const hookResolved = hookPropertyMap.get(request)
  if (hookResolved) request = hookResolved
  return resolveFilename.call(mod, request, parent, isMain, options)
}

tDomDir}/server.edge`],
])

const resolveFilename =


atcherObject = {
  pathname: string
  search?: string
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'HEAD' | 'OPTIONS'
}

export type RequestMatcher =
  | RequestMatcherObject
  | ((request: PlaywrightRequest) => Promise<boolean>)

export type RequestTracker = ReturnType<typeof createRequestTracker>

/** Allows capturing responses to requests that happened as a result of running a callback. */
export function createRequestTracker(browser: Playwright) {
  /** Run a callback and capture requests with the give

 ): Promise<[result: T, captured: PlaywrightResponse]> {
    const isMatchingRequest = async (request: PlaywrightRequest) => {
      if (typeof requestMatcher === 'function') {
        // This can be async to allow matching on things like `request.allHeade

n `method` and `pathname`. */
  async function captureResponse<T>(
    action: () => Promise<T>,
    {
      request: requestMatcher,
      timeoutMs = 5000,
    }: {
      request: RequestMatcher
      timeoutMs?: number
    }


te _deploymentId: string | undefined
  private _supportsImmutableAssets: boolean = false
  private _cliOutput: string = ''

  private _prerenderFinishedTimeMS: number | null = null

  constructor(opts: NextInstanceOpts) {
    super(opts)

    if (!opts.disableAutoSkewProtection && shouldUseTurbopack()) {
      this.env.NEXT_DEPLOYMENT_ID = 'test-dpl-id-1234'
      this.env.__NEXT_SUPPORTS_IMMUTABLE_ASSETS = '1'
    }
  }

  public get buildId() {
    return this._buildId
  }

  public get deploymentId() {

async setup(parentSpan: Span) {
    super.setup(parentSpan)
    await super.createTestDir({ parentSpan })
  }

  private handleStdio = (childProcess) => {
    childProcess.stdout.on('data', (chunk) => {
      const msg = chunk.toString()
      process.stdo

   return this._deploymentId
  }

  public get supportsImmutableAssets() {
    return process.env.IS_TURBOPACK_TEST ? this._supportsImmutableAssets : false
  }

  public get cliOutput() {
    return this._cliOutput
  }

  public


 debugPrint = (...args: unknown[]) => {
  const prettyArgs = args
    .map((arg) =>
      typeof arg === 'string'
        ? arg
        : inspect(arg, { colors: process.stdout.isTTY })
    )
    .join(' ')

  const timestamp = new Date().toISOString().split('T')[1]

  return process.stdout.write(`[${timestamp}] ${prettyArgs}\n`)
}

export function initNextServerScript(
  scriptPath: string,
  successRegexp: RegExp,
  env: NodeJS.ProcessEnv,
  failRegexp?: RegExp,
  opts?: {
    cwd?: string
    nodeArgs?: s

turn new Promise((resolve, reject) => {
    const instance = spawn(
      'node',
      [...((opts && opts.nodeArgs) || []), '--no-deprecation', scriptPath],
      {
        env: { HOSTNAME: '::', ...env },
        cwd: opts && opts.cwd,
      }
    )

tring[]
    onStdout?: (data: any) => void
    onStderr?: (data: any) => void
    // If true, the promise will reject if the process exits with a non-zero code
    shouldRejectOnError?: boolean
  }
): Promise<ChildProcess> {
  re


des/next-deploy'
import { shouldUseTurbopack } from '../next-test-utils'

export type { NextInstance }
export type { Playwright } from '../browsers/playwright'

const individualTestTimeout = 60 * 1000

// Keep a higher timeout for setup hooks (e.g. initial createNext/startup),
// but enforce 60s per test case via wrapped `it`/`test` for non-dev modes.
let setupTimeout = (process.platform === 'win32' ? 240 : 120) * 1000

if (process.env.NEXT_E2E_TEST_TIMEOUT) {
  const parsedTimeout = Number.parseInt(process

  __NEXT_E2E_WRAPPED_TEST_FNS__?: WeakMap<Function, Function>
}

const wrapJestTestFn = <T extends Function>(fn: T): T => {
  const e2eGlobal = global as E2ETestGlobal
  const wrappedFns =
    e2eGlobal.__NEXT_E2E_WRAPPED_TEST_FNS__ ??
    (e2eGlobal.__NEX

.env.NEXT_E2E_TEST_TIMEOUT, 10)
  if (!Number.isNaN(parsedTimeout)) {
    setupTimeout = parsedTimeout
  }
}

jest.setTimeout(setupTimeout)

type E2ETestGlobal = typeof globalThis & {
  __NEXT_E2E_TEST_CONFIG_PATCHED__?: boolean


T_TEST_USE_RSPACK === '1'
const ROOT_PACKAGE_MANAGER = require('../../package.json').packageManager

async function installDependencies(cwd, tmpDir) {
  const args = [
    'install',
    '--strict-peer-dependencies=false',
    '--no-frozen-lockfile',
    `--config.cacheDir=${tmpDir}`,
  ]

  if (PREFER_OFFLINE) {
    args.push('--prefer-offline')
  }

  await execa('pnpm', args, {
    cwd,
    stdio: ['ignore', 'inherit', 'inherit'],
    env: {
      ...process.env,
      // pnpm reads this despite claims i

nment variables
      // so some installs would just fail.
      // TODO: ideally every test fixture would run with minimumReleaseAgeExclude but
      // that requires some work in monorepo test suites.
      npm_config_minimum_release_age: undefined,

t ignores `npm_config_*` env variables.
      // This isn't set in CI but some local environments set this from the
      // pnpm-workspace.yaml for unknown reasons.
      // minimumReleaseAgeExclude is not propagated with enviro


k from 'next/link'

export default function Page() {
  // NOTE: these links must be kept in sync with `path` variables used in the test
  return (

          <Link href="/simple">/simple</Link>

          <Link href="/private-cache">/private-cache</Link>

          <Link href="/short-lived-cache">/short-lived-cache</Link>

          <Link href="/successive-caches">/successive-caches</Link>

          <Link href="/apis/123">/apis/123</Link>

          <Link href="/sync-io/static">/sync-io/static</Link>

          <Link href="/sync-io/runtime">/sync-io/runtime</Link>


('app-dir - owner-stack-invalid-element-type', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should catch invalid element from a browser only component', async () => {
    const browser = await next.browser('/browser')

    await expect(browser).toDisplayRedbox(`
     {
       "description": "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the fi

-only.js (8:7) @ BrowserOnly
     >  8 |       <Foo />
          |       ^",
       "stack": [
         "BrowserOnly app/browser/browser-only.js (8:7)",
         "Inner app/browser/page.js (11:10)",
         "Page app/browser/page.js (15:10)",
       ],

le it's defined in, or you might have mixed up default and named imports.

     Check the render method of \`BrowserOnly\`.",
       "environmentLabel": null,
       "label": "Runtime Error",
       "source": "app/browser/browser


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

  it('should update parallel routes via HMR', async () => {
    const browser = await next.browser('/')
    expect(await browser.elementByCss('#bar').text()).toBe('Bar Page')
    expect(await browser.elementByCss('#foo').text()).toBe('Foo Page')

    await next.patchFile('app/@bar/page.tsx', (content) =>
      content.replace('Bar Page', 'Bar Page Updated')
    )

    await waitForNoRedbox(browser)

    exp

'Bar Page Updated')

    await next.patchFile('app/@foo/page.tsx', (content) =>
      content.replace('Foo Page', 'Foo Page Updated')
    )

    await waitForNoRedbox(browser)

    expect(await browser.elementByCss('#foo').text()).toBe('Foo Page Updated')


mport { execSync } from 'node:child_process'
import { getCacheDirectory } from 'next/dist/lib/helpers/get-cache-directory'
import { nextTestSetup } from 'e2e-utils'
import { parseTraceFile } from '../../../lib/parse-trace-file'

describe('rage restart trace attributes', () => {
  // Use a fake upload URL so traceUploadUrl is set and detection runs.
  // The URL doesn't need to be reachable — we inspect the trace file directly.
  const fakeUploadUrl = 'http://localhost:19999'

  const { next, isNextDev } = n

StateFilePath = () =>
    join(getCacheDirectory('nextjs-nodejs'), 'dev-state.json')

  beforeEach(async () => {
    // Ensure each test starts from a clean stopped state with no prior session.
    await next.stop('SIGTERM').catch(() => {})
    rmSync(getD

extTestSetup({
    files: __dirname,
    skipStart: true,
    startArgs: ['--experimental-upload-trace', fakeUploadUrl],
  })

  if (!isNextDev) {
    it('should be skipped in production', () => {})
    return
  }

  const getDev


ck,
} from 'next-test-utils'

describe('app-dir - owner-stack-react-missing-key-prop', () => {
  const { isTurbopack, next } = nextTestSetup({
    files: __dirname,
  })

  it('should catch invalid element from on rsc component', async () => {
    const browser = await next.browser('/rsc')
    await openRedbox(browser)

    const stackFramesContent = await getRedboxCallStack(browser)
    const source = await getRedboxSource(browser)

    if (isTurbopack) {
      expect(stackFramesContent).toMatchInlineSnaps

"app/rsc/page.tsx (7:9) @ <anonymous>

            5 |

            6 |       {list.map((item, index) => (
         >  7 |         {item}
              |         ^
            8 |       ))}
            9 |

hot(`
       [
         "span <anonymous>",
         "<anonymous> app/rsc/page.tsx (7:9)",
         "Array.map <anonymous>",
         "Page app/rsc/page.tsx (6:13)",
       ]
      `)
      expect(source).toMatchInlineSnapshot(`


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

const cacheComponentsEnabled = process.env.__NEXT_CACHE_COMPONENTS === 'true'

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

  it('shows Cache Components indicator when enabled', async () => {
    await next.fetch('/')
    await retry(async () => {
      const output = next.cliOutput

      if (cacheComponentsEnabled) {
        if (isTurbopack) {
          expect(output).

k')
          expect(output).toContain('Cache Components')
        }
      } else {
        // When cache components env is not set, should not show the indicator
        expect(output).toContain('Next.js')
        if (isTurbopack) {
          expect(outpu

toContain('Next.js')
          expect(output).toContain('Turbopack')
          expect(output).toContain('Cache Components')
        } else {
          expect(output).toContain('Next.js')
          expect(output).toContain('webpac


    const nextDevBootstrapOutputIndex = next.cliOutput.length

    const browser = await next.browser('/request/cookies')

    const browserLogs = await browser.log()
    const browserConsoleWarnings = browserLogs
      .filter((log) => log.source === 'warning')
      .map((log) => log.message)
    const terminalOutput = next.cliOutput.slice(nextDevBootstrapOutputIndex)
    const terminalCookieErrors = terminalOutput.split('\n').filter((line) => {
      return line.includes('Route "/request/cookies')
    }

})
  })

  it('warnings on sync draftMode access', async () => {
    const nextDevBootstrapOutputIndex = next.cliOutput.length

    const browser = await next.browser('/request/draftMode')

    const browserLogs = await browser.log()
    const browserConso

)
    expect({ browserConsoleWarnings, terminalCookieErrors }).toEqual({
      browserConsoleWarnings: [expect.stringContaining('`cookies().get`.')],
      terminalCookieErrors: [expect.stringContaining('`cookies().get`.')],


from 'e2e-utils'
import { retry } from 'next-test-utils'
import stripAnsi from 'strip-ansi'

// turbopack.ignoreIssue only works with Turbopack
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
  'css-parse-error-recovery',
  () => {
    describe('with turbopack.ignoreIssue config', () => {
      const { next, skipped } = nextTestSetup({
        files: __dirname,
        nextConfig: {
          turbopack: {
            ignoreIssue: [
              {
                path: '**/css-error/**',

s.status).toBe(200)
        const html = await res.text()
        expect(html).toContain('css error page')
      })

      it('should suppress CSS parse error from cli output when ignored', async () => {
        const outputIndex = next.cliOutput.length

        },
            ],
          },
        },
      })

      if (skipped) return

      it('should render page with ignored CSS parse error', async () => {
        const res = await next.fetch('/css-error')
        expect(re


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

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

  it('should create dev artifacts in .next/dev/ directory', async () => {
    await retry(async () => {
      expect(await next.hasFile('.next/dev')).toBe(true)
      expect(await next.hasFile('.next/server')).toBe(false)
    })
  })

  it('should work with HMR', async () => {
    const browser = await next.browser('/')
    expect(aw

rld')

    await next.patchFile('app/page.tsx', (content) => {
      return content.replace('hello world', 'hello updated world')
    })

    await retry(async () => {
      expect(await browser.elementByCss('p').text()).toBe('hello updated world')
    })


('server-navigation-error', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  describe('pages router', () => {
    it('should error on navigation API redirect', async () => {
      const browser = await next.browser('/pages/redirect')

      await expect(browser).toDisplayRedbox(`
       {
         "code": "E394",
         "description": "Next.js navigation API is not allowed to be used in Pages Router.",
         "environmentLabel": null,
         "label": "Runtime Error",
         "

error on navigation API notFound', async () => {
      const browser = await next.browser('/pages/not-found')

      await expect(browser).toDisplayRedbox(`
       {
         "code": "E1041",
         "description": "Next.js navigation API is not allowed t

source": "pages/pages/redirect.tsx (4:11) @ Page
       > 4 |   redirect('/')
           |           ^",
         "stack": [
           "Page pages/pages/redirect.tsx (4:11)",
         ],
       }
      `)
    })

    it('should


to restart
    if (isStarted) {
      await next.stop()
    }
    await next.start()
    isStarted = true
  })

  it('explicit react-dom/server.browser usage in app code', async () => {
    const browser = await next.browser(
      '/exports/app-code/react-dom-server-browser-explicit'
    )

    await waitForNoRedbox(browser)
    if (isTurbopack) {
      expect(await browser.elementByCss('main').text()).toMatchInlineSnapshot(`
        "{
          "default": [
            "renderToReadableStream",

",
            "renderToString",
            "resume",
            "version"
          ]
        }"
      `)
    } else {
      expect(await browser.elementByCss('main').text()).toMatchInlineSnapshot(`
        "{
          "default": [
            "renderT

   "renderToStaticMarkup",
            "renderToString",
            "resume",
            "version"
          ],
          "named": [
            "default",
            "renderToReadableStream",
            "renderToStaticMarkup


t detected)', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    env: { CLAUDECODE: '1' },
  })

  it('creates AGENTS.md and CLAUDE.md at the project root when neither exists', async () => {
    // A request is required to synchronize the test with the auto-gen
    // hook — `✓ Ready in X` is logged before the config load that runs
    // the hook, so `next.start()` resolves too early. `next.fetch` blocks
    // on the request handler, which only becomes ready after the hook.
    await nex

xt/dist/docs/')

    const claudeContent = fs.readFileSync(
      path.join(next.testDir, 'CLAUDE.md'),
      'utf-8'
    )
    expect(claudeContent).toBe('@AGENTS.md\n')
  })
})

describe('agent-rules auto-generate on next dev (no agent)', () => {
  const

t.fetch('/')

    const agentsContent = fs.readFileSync(
      path.join(next.testDir, 'AGENTS.md'),
      'utf-8'
    )
    expect(agentsContent).toContain(AGENT_RULES_MARKER)
    expect(agentsContent).toContain('node_modules/ne


apseCallStackFrames,
} from 'next-test-utils'

describe('error-ignored-frames', () => {
  const { isTurbopack, next } = nextTestSetup({
    files: __dirname,
  })

  it('should be able to collapse ignored frames in server component', async () => {
    const browser = await next.browser('/')
    await waitForRedbox(browser)

    const defaultStack = await getRedboxCallStack(browser)
    expect(defaultStack).toMatchInlineSnapshot(`
     [
       "Page app/page.tsx (2:9)",
     ]
    `)

    await toggleCollap

tack trace that was ignore-listed.
    // It'll contain implementation details that may change and
    // shouldn't break this test.
    expect(ignoreListedStack).not.toHaveLength(0)
  })

  it('should be able to collapse ignored frames in client component

seCallStackFrames(browser)

    const expandedStack = await getRedboxCallStack(browser)
    const ignoreListedStack = expandedStack.filter(
      (line) => !defaultStack.includes(line)
    )
    // We don't care about the exact s


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

describe('duplicate-runtime-error', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not rerender the overlay for the same runtime error', async () => {
    const browser = await next.browser('/')
    const badge = await browser.elementByCss('[data-next-badge]')

    // Wait until the badge is showing "errored"
    await retry(async () => {
      const errorProp = await badge.getAttribute('data-error')

      expect(

 the same value after a while without re-rendersw.
    // Should always display the badge, should not re-render by hiding it again
    for (let i = 0; i < 40; i++) {
      const errorProp = await badge.getAttribute('data-error')

      expect(errorProp).to

errorProp).toBe('true')
    })

    // Still present


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

describe('app-dir - async-client-component', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('app router client component async module', async () => {
    const browser = await next.browser('/client')

    // There is no stack since this error is issued from the owner
    // which is a Next.js Component.
    // Ideally, it would be issued from the async Component instead but that's
    // ha

s error is often caused by accidentally adding \`'use client'\` to a module that was originally written for the server.",
         "environmentLabel": null,
         "label": "Console Error",
         "source": null,
         "stack": [],
       },

rder to implement.
    await expect(browser).toDisplayCollapsedRedbox(`
     [
       {
         "code": "E394",
         "description": "<Page> is an async Client Component. Only Server Components can be async at the moment. Thi


ames in assertions.
function normalizeBrowserConsoleStackTrace(trace: unknown) {
  if (typeof trace !== 'string') {
    return trace
  }
  return (
    trace
      // Removes React's internals i.e. incomplete ignore-listing
      .split(
        /at (react-stack-bottom-frame|Object\.react_stack_bottom_frame).*/m
      )[0]
      // Remove the location `()` part in every line of stack trace;
      .replace(/\(.*\)/g, '')
      // Remove the leading spaces in every line of stack trace;
      .replace(/^\s+/gm

errorStack: string | undefined
    const browser = await next.browser('/browser/uncaught', {
      beforePageLoad: (page) => {
        page.on('pageerror', (error: unknown) => {
          errorStack = (error as any).stack
        })
      },
    })

    if

, '')
      .trim()
  )
}

describe('app-dir - owner-stack', () => {
  const { isTurbopack, next } = nextTestSetup({
    files: __dirname,
  })

  it('should log stitched error for browser uncaught errors', async () => {
    let


t webdriver from 'next-webdriver'
import { join } from 'path'
import {
  resolveNextTgzFilename,
  run,
  useTempDir,
} from '../../../production/create-next-app/utils'

const TEST_TIMEOUT_MS = 5 * 60 * 1000

describe('create-next-app default template', () => {
  let nextTgzFilename: string

  beforeAll(() => {
    nextTgzFilename = resolveNextTgzFilename()
  })

  it(
    'should create and run without browser warnings or errors',
    async () => {
      await useTempDir(async (cwd) => {
        const proj

     {
            cwd,
          }
        )

        expect(exitCode).toBe(0)

        const dir = join(cwd, projectName)
        const nextBin = join(dir, 'node_modules/next/dist/bin/next')
        const port = await findPort()
        const server = sp

ectName = 'default-app'
        const { exitCode } = await run(
          [
            projectName,
            '--yes',
            ...(process.env.NEXT_RSPACK ? ['--rspack'] : []),
          ],
          nextTgzFilename,


utils'

describe('app dir - dynamic error trace', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
  })
  if (skipped) return

  it('should show the error trace', async () => {
    const browser = await next.browser('/')

    // TODO(veil): Where is the stackframe for app/page.js?
    await expect(browser).toDisplayRedbox(`
     {
       "code": "E828",
       "description": "Route / with \`dynamic = "error"\` couldn't be rendered statically because it used \`headers()\`. See more i

application/rendering/static-and-dynamic#dynamic-rendering",
       "environmentLabel": "Server",
       "label": "Runtime Error",
       "source": "app/lib.js (4:13) @ Foo
     > 4 |   useHeaders()
         |             ^",
       "stack": [
         "Fo


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

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

  it('should do HMR when rendering two server component changes at the same time', async () => {
    let browser = await next.browser('/page1')

    expect(
      await (await (await browser.elementByCss('iframe')).contentFrame())
        .locator('p')
        .innerText()
    ).toEqual('content')

    let cliOutputLength = ne

('iframe')).contentFrame())
        .locator('p')
        .innerText()
    ).toEqual('content-new')

    const cliOutput = next.cliOutput.slice(cliOutputLength)
    expect(cliOutput).not.toContain('Error')
    expect(cliOutput).not.toContain('Could not fin

xt.cliOutput.length

    await next.patchFile('app/page2/page.tsx', (content) =>
      content.replace('content', 'content-new')
    )

    await waitForNoRedbox(browser)
    expect(
      await (await (await browser.elementByCss


figs',
    hasRuntimePrefetch: false,
    fixturePath: 'fixtures/without-prefetch-config',
  },
  {
    description: 'with runtime prefetch configs',
    hasRuntimePrefetch: true,
    fixturePath: 'fixtures/with-prefetch-config',
  },
])(
  'cache-components-tasks - $description',
  ({ fixturePath, hasRuntimePrefetch }) => {
    const { next, isTurbopack, isNextDev } = nextTestSetup({
      files: nodePath.join(__dirname, fixturePath),
    })

    function assertLog(
      logs: Array<{ source: string; mess

che|Prerender|Prefetch|Prefetchable|Server)\\b).*`
      )
      const logMessages = logs.map((log) => log.message)
      const messages = logMessages.filter((message) => logPattern.test(message))

      // If there's zero or more than one logs that match,

age: string }>,
      message: string,
      expectedEnvironment: string
    ) {
      // Match logs that contain the message, with any environment.
      const logPattern = new RegExp(
        `^(?=.*\\b${message}\\b)(?=.*\\b(Ca


rs'
import { connection } from 'next/server'

function immediate() {
  return new Promise<void>((resolve) => setImmediate(resolve))
}

export async function Static({ label }: { label: string }) {
  await immediate()
  await immediate()
  console.log(`after immediate - static - ${label}`)
  return
Static - {label}

}

export async function Runtime({ label }: { label: string }) {
  await cookies()
  console.log(`after cookies - ${label}`)
  await immediate()
  await immediate()
  console.log(`after

me - {label}</div>
}

export async function Dynamic({ label }: { label: string }) {
  await connection()
  console.log(`after connection - ${label}`)
  await immediate()
  await immediate()
  console.log(`after immediate - dynamic - ${label}`)
  return <di

immediate - runtime - ${label}`)
  return <div>Runti


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

describe('logging-incoming-request', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not log requests matching ignore pattern', async () => {
    // Make requests that should be ignored based on config

    let response = await next.fetch('/hello')
    expect(response.status).toBe(200)

    response = await next.fetch('/non-existent')
    expect(response.status).toBe(404)

    response = aw

   expect(next.cliOutput).not.toContain('GET /hello')
      expect(next.cliOutput).not.toContain('GET /non-existent')
      expect(next.cliOutput).not.toContain('GET /_next/static/test.js')
      expect(next.cliOutput).toContain('GET /foo')
    })
  })
})

ait next.fetch('/_next/static/test.js')
    expect(response.status).toBe(404)

    // Make a request that should be logged
    response = await next.fetch('/foo')
    expect(response.status).toBe(200)

    await retry(() => {


 it.skip

  describe('module preservation', () => {
    itTurbopackDev(
      'does not re-evaluate an unmodified module when page module changes',
      async () => {
        const browser = await next.browser('/module-preservation')

        // Wait for initial render with module timestamp
        await retry(async () => {
          const text = await browser.elementByCss('#module-eval-time').text()
          expect(text).toMatch(/Module Evaluated At: \d+/)
        })

        // Capture the initial modul

it next.patchFile('app/module-preservation/page.tsx', (content) =>
          content.replace('hello world', 'hello universe')
        )

        // Wait for HMR to apply and verify the page updated
        await retry(async () => {
          const text = a

e evaluation timestamp
        const initialModuleEvalTime = await browser
          .elementByCss('#module-eval-time')
          .text()

        // Make a change to the page that doesn't affect the unmodified module
        awa


outdent'

describe('Cache Components Dev Errors', () => {
  const { isTurbopack, next, isRspack } = nextTestSetup({
    files: __dirname,
  })

  it('should show a red box error on the SSR render', async () => {
    const browser = await next.browser('/error')

    // TODO(veil): The "Page <anonymous>" frame should be omitted.
    // Interestingly, it only appears on initial load, and not when
    // soft-navigating to the page (see test below).
    await expect(browser).toDisplayCollapsedRedbox(`
     {

 Page
     > 2 |   const random = Math.random()
         |                       ^",
       "stack": [
         "Page app/error/page.tsx (2:23)",
         "Page <anonymous>",
       ],
     }
    `)
  })

  it('should not show a red box error on client nav

     "code": "E1261",
       "description": "Next.js encountered the unstable value Math.random() while prerendering.",
       "environmentLabel": "Server",
       "label": "Instant",
       "source": "app/error/page.tsx (2:23) @


tring) {
  return fetchCached(
    `https://next-data-api-endpoint.vercel.app/api/random?key=${encodeURIComponent('cached-' + cacheKey)}`
  )
}

export async function fetchCached(url: string) {
  const response = await fetch(url, { cache: 'force-cache' })
  return response.text()
}

export async function getCachedData(_key: string) {
  'use cache'
  await new Promise((r) => setTimeout(r))
  return Math.random()
}

export async function CachedData({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: strin

 label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {
  // This components tests if we correctly handle the case where resolving a cache
  // reveals another cache in the children. When we're filling caches, we should fill both.
  const data1 =

g
}) {
  const data = await getCachedData(cacheKey)
  console.log(`after cache read - ${label}`)
  return (

Cached Data

{data}

  )
}

export async function SuccessiveCachedData({


function PrivateCachedData({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {
  const data = await getPrivateCachedData(cacheKey)
  console.log(`after private cache read - ${label}`)
  return (

Private Cached Data (Page)

{data}

  )
}

export async function SuccessivePrivateCachedData({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {
  // This components tests if we correctly handle the case where resolving a cache
  // reve

{data1}

        <SuccessivePrivateCachedDataChild label={label} cacheKey={cacheKey} />

  )
}

async function SuccessivePrivateCachedDataChild({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {

als another cache in the children. When we're filling caches, we should fill both.
  const data1 = await getPrivateCachedData(`${cacheKey}-successive-1`)
  return (

Private Cached Data (successive reads)


Suspense } from 'react'
import { CachedData, UncachedFetch } from '../data-fetching'
import { PrivateCachedData, SuccessivePrivateCachedData } from './data-fetching'

const CACHE_KEY = '/private-cache/__PAGE__'

export default async function Page() {
  return (

Warmup Dev Renders - private cache

      <CachedData label="page" cacheKey={CACHE_KEY} />

      <Suspense fallback="Loading private cache...">
        <PrivateCachedData label="page" cacheKey={CACHE_KEY} />
      </Suspen

e private caches...">
        <SuccessivePrivateCachedData label="page" cacheKey={CACHE_KEY} />
      </Suspense>

      <Suspense fallback="Loading uncached fetch...">
        <UncachedFetch label="page" cacheKey={CACHE_KEY} />
      </Suspense>
    </mai

se>

      <Suspense fallback="Loading two successiv


k from 'next/link'

export default function Page() {
  // NOTE: these links must be kept in sync with `path` variables used in the test
  return (

          <Link href="/simple">/simple</Link>

          <Link href="/private-cache">/private-cache</Link>

          <Link href="/short-lived-cache">/short-lived-cache</Link>

          <Link href="/successive-caches">/successive-caches</Link>

          <Link href="/apis/123">/apis/123</Link>

          <Link href="/sync-io/static">/sync-io/static</Link>

          <Link href="/sync-io/runtime">/sync-io/runtime</Link>


} from 'react'
import { UncachedFetch, CachedData } from '../data-fetching'
import { PrivateCachedData } from './data-fetching'

export const unstable_instant = true
export const unstable_prefetch = 'force-runtime'

const CACHE_KEY = '/private-cache/__LAYOUT__'

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

Layout

This data is from a layout

        <CachedData label="layout" cacheKey={CACHE_K

cache...">
          <PrivateCachedData label="layout" cacheKey={CACHE_KEY} />
        </Suspense>

        <Suspense fallback="Loading uncached fetch...">
          <UncachedFetch label="layout" cacheKey={CACHE_KEY} />
        </Suspense>
      </section>

EY} />

        <Suspense fallback="Loading private


m 'react'
import { UncachedFetch, CachedData } from '../data-fetching'
import { ShortLivedCache } from './data-fetching'

export const unstable_instant = true
export const unstable_prefetch = 'force-runtime'

const CACHE_KEY = __dirname + '/__LAYOUT__'

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

Layout

This data is from a layout

        <CachedData label="layout" cacheKey={CACHE_KEY} />

..">
          <ShortLivedCache label="layout" cacheKey={CACHE_KEY} />
        </Suspense>

        <Suspense fallback="Loading uncached fetch...">
          <UncachedFetch label="layout" cacheKey={CACHE_KEY} />
        </Suspense>
      </section>
    </>

<Suspense fallback="Loading short-lived cache.


from 'e2e-utils'
import { waitForNoRedbox, hasErrorToast } from 'next-test-utils'

describe('ssr-only-error', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should show ssr only error in error overlay', async () => {
    const browser = await next.browser('/')

    // TODO(veil): Missing Owner Stack (NDX-905)
    await expect(browser).toDisplayCollapsedRedbox(`
     {
       "code": "E394",
       "description": "SSR only error",
       "environmentLabel": null,
       "label":

)

  it('should not handle internal nextjs errors that will be handled by error boundaries', async () => {
    const browser = await next.browser('/notfound', {
      pushErrorAsConsoleLog: true,
    })

    await waitForNoRedbox(browser)
    expect(await

 "Runtime Error",
       "source": "app/page.tsx (5:11) @ Component
     > 5 |     throw new Error('SSR only error')
         |           ^",
       "stack": [
         "Component app/page.tsx (5:11)",
       ],
     }
    `)
  }


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

describe('develop - app-dir - edge errros hmr', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should recover from build errors when server component error', async () => {
    const browser = await next.browser('/')
    const clientComponentSource = await next.readFile('app/comp.server.js')

    await next.patchFile('app/comp.server.js', (content) => {
      return content.repl

hen client component error', async () => {
    const browser = await next.browser('/')
    const clientComponentSource = await next.readFile('app/comp.client.js')

    await next.patchFile('app/comp.client.js', (content) => {
      return content.replace('

ace('{/* < */}', '<') // uncomment
    })

    await waitForRedbox(browser)

    await next.patchFile('app/comp.server.js', clientComponentSource)

    await waitForNoRedbox(browser)
  })

  it('should recover from build errors w


        "code": "E394",
           "componentStack": "...
           <Next.js Internal Component>
             <Next.js Internal Component>
               <Next.js Internal Component>
                 <Next.js Internal Component>
                   <Next.js Internal Component>
                     <Next.js Internal Component>
                       <Next.js Internal Component>
                         <Next.js Internal Component>
                           <Next.js Internal Component>

mise}>
       >

       >

                             ...
                           ...
                 ...",
           "description": "In HTML,
 cannot be a descendant of
.
       This

       <Next.js Internal Component>
                               <Next.js Internal Component>
                               <Next.js Internal Component>
                                 <Page params={Promise} searchParams={Pro


ad: boolean | Promise<void>
  }
}

if (!globalThis._testState) {
  globalThis._testState = {
    initialized: false,
    reload: false,
  }
}

export const subscribeToHMR = async () => {
  const state = globalThis._testState

  if (state.initialized) {
    if (state.reload === true) {
      let resolve: () => void
      state.reload = new Promise<void>((res) => (resolve = res))
      await new Promise((resolve) => setTimeout(resolve, 200))
      resolve()
    }

    if (state.reload instanceof Promise) {

e.initialized = true

  const ws = new WebSocket(`ws://localhost:${process.env.PORT}/_next/hmr`)

  ws.onmessage = (event: any) => {
    if (typeof event.data === 'string') {
      const data = JSON.parse(event.data)
      if (data.type === 'serverComponen

    await state.reload
    }

    return
  }

  stat


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

describe('app-dir watch-config-file', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'fixture'),
  })

  it('should output config file change and restart server for app router', async () => {
    await check(async () => next.cliOutput, /ready/i)

    await check(async () => {
      await next.patchFile(
        'next.config.js',
        `
            console.log(${Date.now()})
            const nextConfig = {

,
                    },
                  ]
                },
            }
            module.exports = nextConfig`
      )
      return next.cliOutput
    }, /Found a change in next\.config\.js\. Restarting the server to apply the changes\.\.\./)

     reactStrictMode: true,
              async redirects() {
                  return [
                    {
                      source: '/about',
                      destination: '/',
                      permanent: false


s/with-prefetch-config',
  },
])(
  'cache-components-dev-warmup - $description',
  ({ fixturePath, hasRuntimePrefetch }) => {
    const { next, isTurbopack } = nextTestSetup({
      files: nodePath.join(__dirname, fixturePath),
    })

    // Restart the dev server for each test to clear the in-memory cache.
    // We're testing cache-warming behavior here, so we don't want tests to interfere with each other.
    let isFirstTest = true
    beforeEach(async () => {
      if (isFirstTest) {
        // There'

urce: string; message: string }>,
      message: string,
      expectedEnvironment: string
    ) {
      // Match logs that contain the message, with any environment.
      const logPattern = new RegExp(
        `^(?=.*\\b${message}\\b)(?=.*\\b(Cache|Prere

s no point restarting if this is the first test.
        isFirstTest = false
        return
      }

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

    function assertLog(
      logs: Array<{ so


ep successive cache reads</h1>
      <One />
    </main>
  )
}

async function One() {
  const cache1 = await fastCache()
  console.log('after cache 1')
  return <Two cache1={cache1} />
}

async function Two({ cache1 }) {
  const cache2 = await slowCache(1)
  console.log('after cache 2')
  return <Three cache1={cache1} cache2={cache2} />
}

async function Three({ cache1, cache2 }) {
  console.log('after caches 1 and 2')
  const cache3 = await slowCache(2)
  console.log('after cache 3')
  return (
    <div>

2: {cache2}

Cache 3: {cache3}

  )
}

async function fastCache() {
  'use cache'
  return Math.random()
}

async function slowCache(_key: number) {
  'use cache'
  await new Promise((resolve) => setTimeout(resolve))
  retur


export const unstable_instant = true
export const unstable_prefetch = 'force-runtime'

export default async function Page() {
  return (

Warmup Dev Renders - deep successive cache reads

      <One />

  )
}

async function One() {
  const cache1 = await fastCache()
  console.log('after cache 1')
  return <Two cache1={cache1} />
}

async function Two({ cache1 }) {
  const cache2 = await slowCache(1)
  console.log('after cache 2')
  return <Three cache1={cache1} cache2={ca

che 2: {cache2}

Cache 3: {cache3}

  )
}

async function fastCache() {
  'use cache'
  return Math.random()
}

async function slowCache(_key: number) {
  'use cache'
  await new Promise((resolve) => setTimeout(resolve))
  r

che2} />
}

async function Three({ cache1, cache2 }) {
  console.log('after caches 1 and 2')
  const cache3 = await slowCache(2)
  console.log('after cache 3')
  return (

Cache 1: {cache1}

Ca


lient'

import { useEffect } from 'react'

/**
 * This page is to verify that the Dev Tools surface animates as expected and without jank:
 *
 * 1. When the page loads with "1 Issue" present,
 *    no animations should trigger (count change, width growth, etc.).
 *    The surface should assume its intrinsic position immediately,
 *    while still animating when collapsed from (×).
 *
 * 2. When multiple errors come in with little delay inbetween them,
 *    the count _should not_ animate when it changes bec

.
 */

// Play with this between `1` and `2`
// to make sure the surface doesn't animate the plural form (s)
const ERROR_COUNT = 2

export default function Page() {
  const clx = typeof window === 'undefined' ? 'server' : 'client'

  useEffect(() => {

ause it will
 *    look janky when the `deltaMs` between changes is less than the `animationDurationMs`.
 *
 * 3. When another error comes in, and `deltaMs` is greater, the surface should
 *    subtly bounce and animate the count


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

describe('logging-incoming-request', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    overrideFiles: {
      'next.config.js': `
        module.exports = {
          logging: {
            incomingRequests: false
          }
        }
      `,
    },
  })

  it('should handle disabled request logging', async () => {
    let response = await next.fetch('/foo')
    expect(response.status).toBe(200)

    response = await next

0)

    // Wait for GET /foo to be logged
    await retry(() => {
      expect(next.cliOutput).not.toContain('GET /foo')
    })

    // Verify no requests were logged
    expect(next.cliOutput).not.toContain('GET /')
    expect(next.cliOutput).not.toContai

.fetch('/hello')
    expect(response.status).toBe(20


kies, headers } from 'next/headers'
import { CachedData } from '../../data-fetching'
import { connection } from 'next/server'
import { Suspense } from 'react'

export const unstable_instant = true
export const unstable_prefetch = 'force-runtime'

const CACHE_KEY = __dirname + '/__PAGE__'

export default function Page({ params, searchParams }) {
  return (
    <main>
      <p>
        This page checks whether runtime/dynamic APIs resolve in the correct
        stage (regardless of whether we had a cache miss

      <LogAfter label="headers" api={() => headers()} />
      <LogAfter label="params" api={() => params} />
      <LogAfter label="searchParams" api={() => searchParams} />
      {/* Dynamic */}
      <LogAfter label="connection" api={() => connection()}

 or not)
      </p>
      <CachedData cacheKey={CACHE_KEY} label="page" />
      <LogAfter label="--- dynamic stage ---" api={() => connection()} />

      {/* Runtime */}
      <LogAfter label="cookies" api={() => cookies()} />


s'

const cacheComponentsEnabled = process.env.__NEXT_CACHE_COMPONENTS === 'true'

describe('use-cache-errors', () => {
  const { next, isRspack, isTurbopack } = nextTestSetup({
    files: __dirname,
  })

  it('should not show a false-positive compiler error about a misplaced "use cache" directive', async () => {
    // This is a regression test to ensure that an injected React Refresh
    // statement (`var _s = __turbopack_context__.k.signature`) does not
    // interfere with our "use cache" directive m

ait next.browser('/')
    await browser.elementById('action-button').click()
    if (isRspack) {
      // TODO: the source is missing and the stack leaks rspack internals
      await expect(browser).toDisplayRedbox(`
       {
         "description": "Attem

isplacement detection.
    const browser = await next.browser('/')
    await waitForNoRedbox(browser)
  })

  it('should show a runtime error when calling the incorrectly used cache function', async () => {
    const browser = aw


kies, headers } from 'next/headers'
import { CachedData } from '../../data-fetching'
import { connection } from 'next/server'
import { Suspense } from 'react'

const CACHE_KEY = __dirname + '/__PAGE__'

export default function Page({ params, searchParams }) {
  return (
    <main>
      <p>
        This page checks whether runtime/dynamic APIs resolve in the correct
        stage (regardless of whether we had a cache miss or not)
      </p>
      <CachedData cacheKey={CACHE_KEY} label="page" />
      <LogAf

 api={() => params} />
      <LogAfter label="searchParams" api={() => searchParams} />
      {/* Dynamic */}
      <LogAfter label="connection" api={() => connection()} />
    </main>
  )
}

function LogAfter({ label, api }: { label: string; api: () => Pr

ter label="--- dynamic stage ---" api={() => connection()} />

      {/* Runtime */}
      <LogAfter label="cookies" api={() => cookies()} />
      <LogAfter label="headers" api={() => headers()} />
      <LogAfter label="params"


test-utils'

describe('browser-log-forwarding error level', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should only forward error logs to terminal', async () => {
    const outputIndex = next.cliOutput.length
    await next.browser('/')

    await retry(() => {
      const output = next.cliOutput.slice(outputIndex)
      expect(output).toContain('browser error:')
    })

    // Get final output after logs are forwarded
    const output = next.cliOutput.slice(outputIndex)

g hydration noise
    const browserLogs = output
      .split('\n')
      .filter(
        (line) =>
          line.includes('[browser]') &&
          !line.includes('Next.js hydrate callback fire')
      )
      .join('\n')

    expect(browserLogs).toMatc

// Filter to only browser forwarded logs, excludin


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

describe('browser-log-forwarding verbose level', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should forward all logs to terminal', async () => {
    const outputIndex = next.cliOutput.length
    await next.browser('/')

    await retry(() => {
      const output = next.cliOutput.slice(outputIndex)
      expect(output).toContain('[browser] browser error:')
      expect(output).toContain('[browser] browser warn:')

Filter to only browser forwarded logs, excluding noise
    const browserLogs = output
      .split('\n')
      .filter(
        (line) =>
          line.includes('[browser]') &&
          !line.includes('Next.js hydrate callback fire') &&
          !line.i

 expect(output).toContain('[browser] browser log:')
      expect(output).toContain('[browser] browser debug:')
    })

    // Get final output after logs are forwarded
    const output = next.cliOutput.slice(outputIndex)

    //


  getRedboxDescription,
  openRedbox,
  waitForNoRedbox,
  retry,
} from 'next-test-utils'

describe('Cache Components Dev Errors', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should not show a red box error on the SSR render', async () => {
    const browser = await next.browser('/cached')
    await waitForNoRedbox(browser)
    let latestValue = await browser.elementByCss('#value').text()

    await browser.refresh()
    await waitForNoRedbox(browser)
    let priorValue = l

ser)
      let priorValue = latestValue
      latestValue = await browser.elementByCss('#value').text()
      expect(latestValue).not.toBe(priorValue)
    })

    await browser.elementByCss('#refresh').click()
    await retry(async () => {
      await wait

atestValue
    latestValue = await browser.elementByCss('#value').text()

    expect(latestValue).toBe(priorValue)

    await browser.elementByCss('#refresh').click()
    await retry(async () => {
      await waitForNoRedbox(brow


 the dev time warning but will reintroduce it when we add in dev-time prerendering.
// The tests will likely have to change but I'd like to keep the fixture and assertions as a starting point.
describe.skip('dynamic-requests warnings', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  let cliIndex = 0

  it('warns on reading the current time in the prerender portion of a dev render', async () => {
    await next.fetch('/platform/render/time')
    expect(next.cliOutput).not.toContain(

form/prerender/time" used `Date.now()`'
    )
    expect(next.cliOutput).not.toContain(
      'Route "/platform/prerender/time" used `performance.now()`'
    )

    await next.fetch('/platform/prerender/time')
    expect(next.cliOutput).toContain(
      'R

      'Route "/platform/prerender/time" used `Date()`'
    )
    expect(next.cliOutput).not.toContain(
      'Route "/platform/prerender/time" used `new Date()`'
    )
    expect(next.cliOutput).not.toContain(
      'Route "/plat


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

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

  it('should have env types from next config', async () => {
    await retry(async () => {
      const envDTS = await next.readFile(`${next.distDir}/types/env.d.ts`)
      // since NODE_ENV is development, env types will
      // not include production-specific env
      expect(envDTS).not.toContain('FROM_ENV_PROD')
      expect(envDTS).not.toContain(

       /** Loaded from \`.env.development.local\` */
              FROM_ENV_DEV_LOCAL?: string
              /** Loaded from \`.env.local\` */
              FROM_ENV_LOCAL?: string
              /** Loaded from \`.env.development\` */
              FROM_EN

'FROM_ENV_PROD_LOCAL')

      expect(envDTS).toEqual(
        outdent`
        // Type definitions for Next.js environment variables
        declare global {
          namespace NodeJS {
            interface ProcessEnv {


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

describe('app-dir watch-distdir-deletion', () => {
  const { next } = nextTestSetup({
    files: path.join(__dirname, 'fixture'),
  })

  it('should restart the server when distDir is deleted', async () => {
    // Wait for the dev server to be ready
    await retry(async () => {
      expect(next.cliOutput).toMatch(/ready/i)
    })

    // Make a request first to ensure the dev server ha

     recursive: true,
      force: true,
    })

    // Wait for restart message and server to come back up
    await retry(
      async () => {
        expect(next.cliOutput).toMatch(/The directory at .* was deleted/)
      },
      30_000,
      1000

s compiled
    const warmupRes = await next.fetch('/')
    expect(warmupRes.status).toBe(200)

    // Delete .next (which also removes .next/dev, the watched distDir)
    await fs.promises.rm(path.join(next.testDir, '.next'), {


m } from './form'
import defaultAction1, { foo, bar, baz, qux } from './actions1'
import defaultAction2 from './actions2'
import defaultAction3 from './actions3'
import Link from 'next/link'
import { ServerComponent } from './server-component'

export default function Page() {
  const action1 = async () => {
    'use server'

    return 'declarator arrow function expression'
  }

  async function action2() {
    'use server'

    return 'function declaration'
  }

  return (
    <main>
      <ServerComponen

{bar} />
      <Form id="form-6" action={baz} />
      <Form id="form-7" action={qux} />
      <Form id="form-8" action={action1} />
      <Form id="form-9" action={action2} />
      <Form
        id="form-10"
        action={async () => {
          'use s

t />
      <Form id="form-1" action={defaultAction1} />
      <Form id="form-2" action={defaultAction2} />
      <Form id="form-3" action={defaultAction3} />
      <Form id="form-4" action={foo} />
      <Form id="form-5" action=


er } from './hydration-marker'

export default function Page() {
  return (

      <HydrationMarker />

Instant Navigation Mode Demo

        This fixture tests the Instant Navigation Mode toggle
        in Next.js Dev Tools. When enabled, navigations show only the cached or
        prefetched state — dynamic data is not streamed.

How to test

          Open Next.js Dev Tools</s

Click the link below. You should see the loading skeleton instead of
          the final page content.

          Click the blue Instant UI only indicator to unblock dynamic
          data and resume normal navigation.

trong> (click the Next.js logo in the
          corner).

          Toggle Instant Navigation Mode to On. The
          indicator turns blue.


stSetup({
    files: __dirname,
  })

  it('should render the segment explorer for parallel routes', async () => {
    const browser = await next.browser('/parallel-routes')
    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
     "app/ [layout.tsx]
     parallel-routes/ [layout.tsx, page.tsx]
     @bar/ [layout.tsx, page.tsx]
     @foo/ [layout.tsx, page.tsx]"
    `)
    expect(await getSegmentExplorerRoute(browser)).toBe('/parallel-routes')
  })

  it('should render the segment ex

parallel-routes-edge/ [layout.tsx, page.tsx]
     @bar/ [layout.tsx, page.tsx]
     @foo/ [layout.tsx, page.tsx]"
    `)
    expect(await getSegmentExplorerRoute(browser)).toBe('/parallel-routes-edge')
  })

  it('should render the segment explorer for nes

plorer for parallel routes in edge runtime', async () => {
    const browser = await next.browser('/parallel-routes-edge')
    expect(await getSegmentExplorerContent(browser)).toMatchInlineSnapshot(`
     "app/ [layout.tsx]


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

describe('browser-log-forwarding warn level', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should forward warn and error logs to terminal', async () => {
    const outputIndex = next.cliOutput.length
    await next.browser('/')

    await retry(() => {
      const output = next.cliOutput.slice(outputIndex)
      expect(output).toContain('browser error:')
      expect(output).toContain('browser war

it('\n')
      .filter(
        (line) =>
          line.includes('[browser]') &&
          !line.includes('Next.js hydrate callback fire')
      )
      .join('\n')

    expect(browserLogs).toMatchInlineSnapshot(`
     "[browser] browser warn: this is a w

n:')
    })

    // Get final output after logs are forwarded
    const output = next.cliOutput.slice(outputIndex)

    // Filter to only browser forwarded logs, excluding hydration noise
    const browserLogs = output
      .spl


mport { revalidateTag, cacheLife, cacheTag } from 'next/cache'
import { fetchData } from '../api/data'
// import { Suspense } from 'react'
// import { cookies, headers } from 'next/headers'

function InnerComponent({ children }) {
  return {children}
}

async function refresh() {
  'use server'
  revalidateTag('hello')
}

async function reload() {
  'use server'
}

async function Component() {
  'use cache'
  cacheLife({ revalidate: 30 })
  cacheTag('hello')
  return <InnerComponent>

lt async function Home() {
  return (
    <>
      <form action={refresh}>
        <button id="refresh">Refresh</button>
      </form>
      <form action={reload}>
        <button id="reload">Reload</button>
      </form>
      <Component />
    </>
  )
}

{await fetchData()}</InnerComponent>
}

export defau


https://github.com/vercel/next.js/issues/86662.
// The bug from occurs if we have:
// - a cache (which requires warming = a restart in dev)
// - a dynamic function (blocked until the dynamic stage, like an uncached fetch)
//   that dedupes concurrent calls. note that that's not quite the same as caching it,
//   because it gets dropped after finishing.

import { Suspense } from 'react'

export default async function Page() {
  return (

      <Suspense fallback={
Loading...
}>
        <d

  cached(),
    // This fetch going to be blocked on the dynamic stage.
    // That promise should be rejected when restarting.
    // If it's not rejected (like it wasn't before the fix),
    // it'll remain hanging, and we'll never render anything.
    f

iv id="random">
          <DynamicRandom />
        </div>
      </Suspense>
    </main>
  )
}

async function DynamicRandom() {
  const [, random] = await Promise.all([
    // ensure that there's a restart to warm this cache.


ser: Playwright): Promise<void> {
    await retry(async () => {
      const cookie = await browser.eval(() => document.cookie)
      expect(cookie).toMatch(/next-instant-navigation-testing=[^;]+/)
    })
  }

  async function clearInstantModeCookie(browser: Playwright) {
    await browser.eval(() => {
      document.cookie = 'next-instant-navigation-testing=; path=/; max-age=0'
    })
  }

  async function waitForInstantModeCookieAbsent(
    browser: Playwright
  ): Promise<void> {
    await retry(async ()

ser.elementByCss('[data-instant-nav]').click()
  }

  async function clickStartCapturing(browser: Playwright) {
    await browser
      .locator('.instant-nav-capture-button', { hasText: 'Start Capturing' })
      .click()
    await waitForInstantModeCooki

=> {
      const cookie = await browser.eval(() => document.cookie)
      expect(cookie).not.toContain('next-instant-navigation-testing=')
    })
  }

  async function clickInstantNavMenuItem(browser: Playwright) {
    await brow


function PrivateCachedData({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {
  const data = await getPrivateCachedData(cacheKey)
  console.log(`after private cache read - ${label}`)
  return (

Private Cached Data (Page)

{data}

  )
}

export async function SuccessivePrivateCachedData({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {
  // This components tests if we correctly handle the case where resolving a cache
  // reve

{data1}

        <SuccessivePrivateCachedDataChild label={label} cacheKey={cacheKey} />

  )
}

async function SuccessivePrivateCachedDataChild({
  label,
  cacheKey,
}: {
  label: string
  cacheKey: string
}) {

als another cache in the children. When we're filling caches, we should fill both.
  const data1 = await getPrivateCachedData(`${cacheKey}-successive-1`)
  return (

Private Cached Data (successive reads)


c } from 'fs'
import { createServer } from 'http'
import { spawn } from 'child_process'
import { parseTraceFile } from '../../../lib/parse-trace-file'

describe('enabled features in trace', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
    startArgs: ['--no-server-fast-refresh'],
  })

  if (!isNextDev) {
    it('should be skipped in production', () => {})
    return
  }

  it('should record enabled features on root span', async () => {
    const tracePath = join(next.testDir,

wait new Promise((resolve) => setTimeout(resolve, 500))
    }

    const traceStructure = parseTraceFile(tracePath)

    // Verify start-dev-server span has feature tags
    const startDevServerEvents =
      traceStructure.eventsByName.get('start-dev-serv

'.next/dev/trace')

    // Trigger page request to generate traces
    if (!existsSync(tracePath)) {
      const $ = await next.render$('/')
      expect($('p').text()).toBe('hello world')
      await next.stop('SIGTERM')
      a


nents.
describe.skip('source-mapping', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should work with server actions passed to client components', async () => {
    const browser = await next.browser('/')

    expect(await browser.elementByCss('#form-1 p').text()).toBe('initial')
    await browser.elementByCss('#form-1 button').click()
    await retry(async () => {
      expect(await browser.elementByCss('#form-1 p').text()).toBe(
        'default exported arrow function expre

rm-2 p').text()).toBe(
        'default exported anonymous function expression'
      )
    })

    expect(await browser.elementByCss('#form-3 p').text()).toBe('initial')
    await browser.elementByCss('#form-3 button').click()
    await retry(async () =>

ssion'
      )
    })

    expect(await browser.elementByCss('#form-2 p').text()).toBe('initial')
    await browser.elementByCss('#form-2 button').click()
    await retry(async () => {
      expect(await browser.elementByCss('#fo


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

describe('typed-env', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    env: {
      NODE_ENV: 'production',
    },
  })

  it('should have env types from next config', async () => {
    await retry(async () => {
      const envDTS = await next.readFile(`${next.distDir}/types/env.d.ts`)
      // since NODE_ENV is production, env types will
      // not include development-specific env
      expect(envDTS).not.toContain

odeJS {
            interface ProcessEnv {
              /** Loaded from \`.env.production.local\` */
              FROM_ENV_PROD_LOCAL?: string
              /** Loaded from \`.env.local\` */
              FROM_ENV_LOCAL?: string
              /** Loaded

('FROM_ENV_DEV')
      expect(envDTS).not.toContain('FROM_ENV_DEV_LOCAL')

      expect(envDTS).toMatchInlineSnapshot(`
        "// Type definitions for Next.js environment variables
        declare global {
          namespace N


e client'

import { useEffect, useState } from 'react'
import { getValue, getAcceptCallCount, subscribe } from './dep-observer.cjs'

// Track when this module was evaluated (should NOT change on dep update)
const evaluatedAt = Date.now()

export default function DepAcceptCjsPage() {
  const [depValue, setDepValue] = useState(getValue())
  const [acceptCallCount, setAcceptCallCount] = useState(getAcceptCallCount())
  const [evalTime, setEvalTime] = useState<number | null>(null)

  useEffect(() => {
    setEv

: number) => {
      setDepValue(newValue)
      setAcceptCallCount(newCount)
    })
  }, [])

  return (

{depValue}

      {evalTime !== null && (

Parent Evaluated At: {evalTime}

alTime(evaluatedAt)
    // dep-observer.cjs registers module.hot.accept('./dep', cb) in CJS context.
    // When dep.ts changes, the CJS module handles it and notifies subscribers.
    return subscribe((newValue: string, newCount


 { nextTestSetup } from 'e2e-utils'

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

  if (!isTurbopack) {
    it('should skip for webpack', () => {})
    return
  }

  it('should apply raw loader via turbopackUse import assertion', async () => {
    const $ = await next.render$('/')
    expect($('#raw').text()).toBe('Hello from raw text file')
  })

  it('should apply replace loader with options via turbopackUse import assertio

 await next.render$('/')
    expect($('#module-type').text()).toBe('Hello via module type')
  })

  it('should apply identity loader with turbopackModuleType json', async () => {
    const $ = await next.render$('/')
    expect($('#json-type').text()).toBe

n', async () => {
    const $ = await next.render$('/')
    expect($('#replaced').text()).toBe('Value is: turbopackUse works!')
  })

  it('should apply raw loader with turbopackModuleType ecmascript', async () => {
    const $ =


ldcard', () => {
  describe('default behavior', () => {
    const { next } = nextTestSetup({
      files: __dirname,
    })

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

  describe('without baseUrl', () => {
    const { next } = nextTestSetup({
      files: __dirname,
      overrideFiles: {
        'jsconfig.json': JSON.stringify(
          {
            compilerOptions: {

'],
              },
            },
            exclude: ['node_modules', '**/*.test.ts', '**/*.test.tsx'],
          },
          null,
          2
        ),
      },
    })

    it('should resolve a wildcard alias', async () => {
      const $ = await n

    paths: {
                '*': ['./node_modules/*


rip-ansi'
import { nextTestSetup } from 'e2e-utils'

describe('config validation - validation only runs once', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/index.js': `
    export default function Page() {
      return
hello world

    }
    `,
      'next.config.js': `
    module.exports = {
      invalidOption: 'shouldTriggerValidation',
      anotherBadKey: 'anotherBadValue'
    }
    `,
    },
  })

  it('should validate config only once in root process', async () => {

hes
      ? validationHeaderMatches.length
      : 0

    // Count occurrences of specific invalid option mentions
    const invalidOptionMatches = output.match(/invalidOption/g)
    const invalidOptionCount = invalidOptionMatches
      ? invalidOptionMatc

await next.fetch('/')
    const output = stripAnsi(next.cliOutput)
    const validationHeaderMatches = output.match(
      /Invalid next\.config\.js options detected:/g
    )
    const validationHeaderCount = validationHeaderMatc


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

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

  it('should not have any changes in asPath after a bundle rebuild', async () => {
    const browser = await next.browser('/')

    const text = await browser.elementByCss('body').text()
    expect(text).toBe(
      '{ "url": { "query": {}, "pathname": "/", "asPath": "/" } }'
    )

    const originalContent = await next.readFile('pages/_app.js')
    const editedConte

   'replace with this'
    )

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

    await retry(async () => {
      const newContent = await browser.elementByCss('body').text()
      expect(newContent).toBe(
        '{ "url": { "query": {}, "pathna

nt = originalContent.replace(
      'find this',


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

  describe('getServerSideProps', () => {
    it('should update when going from dynamic -> static', async () => {
      const browser = await next.browser('/pages/gssp')

      await waitForStaticIndicator(browser, 'Dynamic')

      // validate static -> dynamic updates
      await browser.elementByCss("[href='/pages']").click()

      await waitForStaticIndicator(browser, 'Static')
    })

    it('should update when going from

ages/gssp']").click()

      await waitForStaticIndicator(browser, 'Dynamic')
    })

    it('should be marked dynamic on first load', async () => {
      const browser = await next.browser('/pages/gssp')

      await waitForStaticIndicator(browser, 'Dynam

 static -> dynamic', async () => {
      const browser = await next.browser('/pages')

      await waitForStaticIndicator(browser, 'Static')

      // validate static -> dynamic updates
      await browser.elementByCss("[href='/p


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

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

      // Check if we'

(window.checkInterval)
    }, 5)
  })()`)
}

describe('Dev Rendering Indicator', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('Shows rendering indicator when navigating between pages', async () => {
    // Ensure both pages a

re showing any status (rendering, compiling, etc.)
      window.showedIndicator = window.showedIndicator || (
        statusElement !== null || (status && status !== 'none')
      )
      if (window.showedIndicator) clearInterval


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

describe('correct tsconfig.json defaults', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/index.tsx': 'export default function Page() {}',
    },
    skipStart: true,
    dependencies: {
      typescript: 'latest',
      '@types/react': 'latest',
      '@types/node': 'latest',
    },
  })

  it('should add `moduleResolution` when generating tsconfig.json in dev', async () => {
    try {
      expect(
        await next.readFile(

.json')
        return content && content !== '{}' ? 'ready' : 'retry'
      }, 'ready')

      const tsconfig = JSON.parse(content)
      expect(next.cliOutput).not.toContain('moduleResolution')

      expect(tsconfig.compilerOptions).toEqual(
        exp

'tsconfig.json').catch(() => false)
      ).toBeFalse()

      await next.start()

      let content: string
      // wait for tsconfig to be written
      await check(async () => {
        content = await next.readFile('tsconfig


   `)
  })

  const port = await findPort()
  await new Promise<void>((res) => {
    server.listen(port, () => res())
  })

  return {
    server,
    port,
  }
}

function withBasePath(basePath: string, path: string) {
  return `${basePath}${path}`
}

function getImageOptimizerPath(basePath: string) {
  return withBasePath(
    basePath,
    `/_next/image?url=${encodeURIComponent(withBasePath(basePath, '/image.png'))}&w=256&q=75`
  )
}

function requestInternalDevScript(
  appPort: string | number,
  baseP

erer: options.referer } : {}),
        'sec-fetch-mode': 'no-cors',
        'sec-fetch-site': 'cross-site',
      },
    }
  )
}

function requestInternalDevMiddleware(
  appPort: string | number,
  basePath: string,
  origin: string
) {
  return fetchViaH

ath: string,
  options: { referer?: string } = {}
) {
  return fetchViaHTTP(
    appPort,
    withBasePath(basePath, '/_next/static/chunks/pages/_app.js'),
    undefined,
    {
      headers: {
        ...(options.referer ? { ref


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

describe('Legacy decorators SWC option', () => {
  describe('with extended tsconfig', () => {
    const { next } = nextTestSetup({
      files: {
        'tsconfig.json': new FileRef(
          join(__dirname, 'legacy-decorators/tsconfig-extended.json')
        ),
        'tsconfig-base.json': new FileRef(
          join(__dirname, 'legacy-decorators/jsconfig.json')
        ),
        pages: new FileRef(join(__dirname, 'legacy-decorators/p

 {
        browser = await next.browser('/')
        const text = await browser.elementByCss('#count').text()
        expect(text).toBe('Current number: 0')
        await browser.elementByCss('#increase').click()
        await check(
          () => browse

ages')),
      },
      dependencies: {
        mobx: '6.3.7',
        'mobx-react': '7.2.1',
      },
    })

    it('should compile with legacy decorators enabled from extended config', async () => {
      let browser
      try


estSetup } from 'e2e-utils'
import { fetchViaHTTP, renderViaHTTP } from 'next-test-utils'

describe.each([[''], ['/docs']])(
  'misc basic dev tests, basePath: %p',
  (basePath: string) => {
    const { next } = nextTestSetup({
      files: {
        pages: new FileRef(join(__dirname, 'misc/pages')),
        public: new FileRef(join(__dirname, 'misc/public')),
      },
      nextConfig: {
        basePath,
      },
    })

    it('should set process.env.NODE_ENV in development', async () => {
      const br

to public files', async () => {
      const data = await renderViaHTTP(next.url, basePath + '/data/data.txt')
      expect(data).toBe('data')

      const legacy = await renderViaHTTP(
        next.url,
        basePath + '/static/legacy.txt'
      )

owser = await next.browser(basePath + '/process-env')
      const nodeEnv = await browser.elementByCss('#node-env').text()
      expect(nodeEnv).toBe('development')
      await browser.close()
    })

    it('should allow access


trong':
      return '**' + styled.value + '**'
    case 'code':
      return '`' + styled.value + '`'
    case 'line':
      return styled.value.map(styledStringToMarkdown).join('')
    case 'stack':
      return styled.value.map(styledStringToMarkdown).join('\n')
    default:
      throw new Error('Unknown StyledString type', styled)
  }
}

function normalizeIssues(issues: Issue[]) {
  return issues
    .map((issue) => ({
      ...issue,
      detail:
        issue.detail && normalizePath(styledStringToMa

((a, b) => {
      const a_ = JSON.stringify(a)
      const b_ = JSON.stringify(b)
      if (a_ < b_) return -1
      if (a_ > b_) return 1
      return 0
    })
}

function raceIterators<T>(iterators: AsyncIterableIterator<T>[]) {
  const nexts = iterator

rkdown(issue.detail)),
      filePath: issue.filePath && normalizePath(issue.filePath),
      source: issue.source && {
        ...issue.source,
        source: normalizePath(issue.source.source.ident),
      },
    }))
    .sort


have polyfilled node.js builtins for the browser correctly', async () => {
    const browser = await next.browser('/')

    await browser.waitForCondition('window.didRender', 15000)

    const data = await browser
      .waitForElementByCss('#node-browser-polyfills')
      .text()
    const parsedData = JSON.parse(data)

    expect(parsedData.vm).toBe(105)
    expect(parsedData.hash).toBe(
      'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
    )
    expect(parsedData.buffer).toBe('hell

dData.https).toBe(true)
    expect(parsedData.os).toBe('\n')
    expect(parsedData.path).toBe('/hello/world/test.txt')
    expect(parsedData.process).toBe('browser')
    expect(parsedData.querystring).toBe('a=b')
    expect(parsedData.stringDecoder).toBe(t

o world')
    expect(parsedData.stream).toBe(true)
    expect(parsedData.assert).toBe(true)
    expect(parsedData.constants).toBe(7)
    expect(parsedData.domain).toBe(true)
    expect(parsedData.http).toBe(true)
    expect(parse


import { waitForNoRedbox, check } from 'next-test-utils'
import { nextTestSetup } from 'e2e-utils'
import stripAnsi from 'strip-ansi'

// TODO: investigate occasional failure
describe.skip('Project Directory Renaming', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/index.js': `
          export default function Page() {
            return
hello world

          }
        `,
    },
    skipStart: true,
    forcedPort: 'random',
  })

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

ove(next.testDir, newTestDir)

    next.testDir = newTestDir

    await check(
      () => stripAnsi(next.cliOutput),
      /Detected project directory rename, restarting in new location/
    )
    await check(async () => {
      return (await browser.eval

()
  })

  it('should detect project dir rename and restart', async () => {
    const browser = await next.browser('/')
    await browser.eval('window.beforeNav = 1')

    let newTestDir = `${next.testDir}-renamed`
    await fs.m


n } from 'path'
import { FileRef, nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'

// TODO: Somehow the warning doesn't show up with Turbopack, even though the transform is not enabled.
// TODO: It no longer shows up with Webpack either in tests.
describe.skip('styled-components SWC transform', () => {
  const { next } = nextTestSetup({
    files: {
      'next.config.js': new FileRef(
        join(__dirname, 'styled-components-disabled/next.config.js')
      ),
      pages: new Fil

{
    let browser
    try {
      // Compile /_error
      browser = await next.browser('/404')
      await browser.loadPage(new URL('/', next.url).toString())

      await retry(async () => {
        const logs = await browser.log()
        expect(logs).t

eRef(join(__dirname, 'styled-components-disabled/pages')),
    },
    dependencies: {
      'styled-components': '6.1.16',
    },
  })

  it('should have hydration mismatch with styled-components transform disabled', async () =>


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

// [TODO]: It is unclear why turbopack takes longer to run this test
// remove once it's fixed
if (process.env.IS_TURBOPACK_TEST) {
  jest.setTimeout(1000 * 60 * 5)
}

describe('TailwindCSS JIT', () => {
  const { next } = nextTestSetup({
    files: {
      'postcss.config.js': new FileRef(
        join(__dirname, 'tailwind-jit/postcss.config.js')
      ),
      'tailwind.config.js': new FileRef(
        join(__dirname, 't

, async () => {
    let browser: Playwright
    try {
      browser = await next.browser('/')
      const text = await browser.elementByCss('.text-6xl').text()
      expect(text).toMatch(/Welcome to/)
      const cssBlue = await browser
        .elementByC

ailwind-jit/tailwind.config.js')
      ),
      pages: new FileRef(join(__dirname, 'tailwind-jit/pages')),
    },
    dependencies: {
      tailwindcss: '2.2.19',
      postcss: '8.3.5',
    },
  })

  it('works with JIT enabled'


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

          Welcome to{' '}

            Next.js!

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

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

Documentation →

              Find in-depth in

 rounded-md">
            pages/index.js
          </code>
        </p>

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


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

// This is implemented in Turbopack, but Turbopack doesn't log the module count.
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'Skipped in Turbopack',
  () => {
    describe('optimizePackageImports - mui', () => {
      const { next } = nextTestSetup({
        env: {
          NEXT_TEST_MODE: '1',
        },
        files: join(__dirname, 'fixture'),

        dependencies

    const $ = await next.render$('/mui')
        expect($('#button').text()).toContain('button')
        expect($('#typography').text()).toContain('typography')

        const browser = await next.browser('/mui')
        await waitForNoRedbox(browser)

: {
          '@mui/material': '5.15.15',
          '@emotion/react': '11.11.1',
          '@emotion/styled': '11.11.0',
        },
      })

      it('should support MUI', async () => {
        // Ensure that MUI is working


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

// This is implemented in Turbopack, but Turbopack doesn't log the module count.
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'Skipped in Turbopack',
  () => {
    describe('optimizePackageImports - basic', () => {
      const { next } = nextTestSetup({
        env: {
          NEXT_TEST_MODE: '1',
        },
        files: join(__dirname, 'fixture'),
        dependencies: {
          'lucide-react': '0.264.0',
          '@headless

const html = await next.render('/recursive')
        expect(html).toContain('
42
')
      })

      it('should support visx', async () => {
        const html = await next.render('/visx')
        expect(html).toContain('<linearGradient')
      })

ui/react': '1.7.17',
          '@heroicons/react': '2.0.18',
          '@visx/visx': '3.3.0',
          'recursive-barrel': '1.0.0',
        },
      })

      it('should handle recursive wildcard exports', async () => {


IceCream,
  BackpackIcon,
  LucideActivity,
  Code,
  Menu,
  SortAsc,
  SortAscIcon,
  LucideSortDesc,
  VerifiedIcon,
  CurlyBraces,
  Slash,
  SquareGantt,
  CircleSlashed,
  SquareKanban,
  SquareKanbanDashed,
  Stars,
  Edit,
  Edit2,
  LucideEdit3,
  TextSelection,
  createLucideIcon,
} from 'lucide-react'

import { Tab, RadioGroup, Transition } from '@headlessui/react'

export function Comp() {
  globalThis.__noop__ = createLucideIcon
  return (
    <>
      <IceCream />
      <BackpackIcon />

quareKanban />
      <SquareKanbanDashed />
      <Stars />
      <Edit />
      <Edit2 />
      <LucideEdit3 />
      <TextSelection />
      <Tab.Group>
        <Tab.List>
          <Tab>Tab 1</Tab>
          <Tab>Tab 2</Tab>
          <Tab>Tab 3</Tab>

<LucideActivity />
      <Code />
      <Menu />
      <SortAsc />
      <SortAscIcon />
      <LucideSortDesc />
      <VerifiedIcon />
      <CurlyBraces />
      <Slash />
      <SquareGantt />
      <CircleSlashed />
      <S


t styled, { css } from 'styled-components'
const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${(props) =>
    props.$primary &&
    css`
      background: white;
      color: black;
    `}
`

export default function Ho

n (
    <div>
      <Button
        href="https://github.com/styled-components/styled-components"
        target="_blank"
        rel="noopener"
        $primary
      >
        GitHub
      </Button>

      <Button href="/docs">Documentation</Button>


fetchViaHTTP, renderViaHTTP } from 'next-test-utils'

describe('styled-components SWC transform', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      'styled-components': '6.1.16',
    },
  })
  async function matchLogs$(browser) {
    let foundLog = false

    const browserLogs = await browser.log()

    browserLogs.forEach((log) => {
      if (log.message.includes('Warning: Prop `%s` did not match.')) {
        foundLog = true
      }
    })
    return foundLog
  }

4')

      // Try 4 times to be sure there is no mismatch
      expect(await matchLogs$(browser)).toBe(false)
      await browser.refresh()
      expect(await matchLogs$(browser)).toBe(false)
      await browser.refresh()
      expect(await matchLogs$(brow

  it('should not have hydration mismatch with styled-components transform enabled', async () => {
    let browser
    try {
      browser = await next.browser('/')

      // Compile /_error
      await fetchViaHTTP(next.url, '/40


 buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${(props) =>
    props.$primary &&
    css`
      background: white;
      color: black;
    `}
`

export default function Home() {
  console.log('__render__')
  return (
    <div
      id="wrap-div"
      css={`

on
        href="https://github.com/styled-components/styled-components"
        target="_blank"
        rel="noopener"
        $primary
      >
        GitHub
      </Button>

      <Button id="btn" href="/docs">
        Documentation
      </Button>

       background: black;
      `}
    >
      <Butt


nextTestSetup } from 'e2e-utils'

export function runBasicHmrTest(nextConfig: {
  basePath: string
  assetPrefix: string
}) {
  const { next, isTurbopack } = nextTestSetup({
    files: __dirname,
    nextConfig,
    patchFileDelay: 500,
    forcedPort: 'random',
  })
  const { basePath } = nextConfig

  it('should have correct router.isReady for auto-export page', async () => {
    let browser = await next.browser(basePath + '/auto-export-is-ready')

    expect(await browser.elementByCss('#ready').text()).t

r.elementByCss('#ready').text()).toBe('yes')
    })
    expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({
      hello: 'world',
    })
  })

  it('should have correct router.isReady for getStaticProps page', async () => {
    let br

oBe('yes')
    expect(JSON.parse(await browser.elementByCss('#query').text())).toEqual({})

    browser = await next.browser(basePath + '/auto-export-is-ready?hello=world')

    await retry(async () => {
      expect(await browse


Output).toContain('GET /hmr/new-page 404')
    let cliOutputLength = next.cliOutput.length

    // Add the page
    await next.patchFile(
      join('pages', 'hmr', 'new-page.js'),
      'export default () => (
the-new-page
)',
      async () => {
        await retry(async () => {
          expect(await getBrowserBodyText(browser)).toMatch(/the-new-page/)
        })
        expect(next.cliOutput.slice(cliOutputLength)).toContain(
          'GET /hmr/new-page 200'
        )
        cli

   )
    })
    expect(next.cliOutput.slice(cliOutputLength)).toContain(
      'GET /hmr/new-page 404'
    )
  })

  it('should recover from 404 after a page has been added with dynamic segments', async () => {
    const browser = await next.browser(basePa

OutputLength = next.cliOutput.length
      }
    )

    // page was deleted at the end of patchFile
    await retry(async () => {
      expect(await getBrowserBodyText(browser)).toMatch(
        /This page could not be found/


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

export function runFullReloadHmrTest(nextConfig: {
  basePath: string
  assetPrefix: string
}) {
  const { next } = nextTestSetup({
    files: __dirname,
    nextConfig,
    patchFileDelay: 500,
  })
  const { basePath } = nextConfig

  it('should warn about full reload in cli output - anonymous page function', async () => {
    const start = next.cliOutput.length
    const browser = await next.browser(
      basePath + '/hmr/anonymous-page-function'
    )

').text()).toBe('hello world')
    expect(next.cliOutput.slice(start)).not.toContain(cliWarning)

    const currentFileContent = await next.readFile(
      './pages/hmr/anonymous-page-function.js'
    )
    const newFileContent = currentFileContent.replace

  const cliWarning =
      'Fast Refresh had to perform a full reload when ./pages/hmr/anonymous-page-function.js changed. Read more: https://nextjs.org/docs/messages/fast-refresh-reload'

    expect(await browser.elementByCss('p


 add it back', () => {
    it('should load the page properly', async () => {
      const contactPagePath = join('pages', 'hmr', 'contact.js')
      const newContactPagePath = join('pages', 'hmr', '_contact.js')
      const browser = await next.browser(basePath + '/hmr/contact')
      try {
        const text = await browser.elementByCss('p').text()
        expect(text).toBe('This is the contact page.')

        expect(next.cliOutput).toMatch(/GET .*\/hmr\/contact 200/)
        let cliOutputLength = next.cli

            /This page could not be found/
          )
        })
        expect(next.cliOutput.slice(cliOutputLength)).toMatch(
          /GET .*\/hmr\/contact 404/
        )
        cliOutputLength = next.cliOutput.length

        // Rename the file back

Output.length

        // Rename the file to mimic a deleted page
        await next.renameFile(contactPagePath, newContactPagePath)

        await retry(async () => {
          expect(await getBrowserBodyText(browser)).toMatch(


or('[data-indicator-status]')
      const badge = root.querySelector('[data-next-badge]')
      const status = badge ? badge.getAttribute('data-status') : null

      // Check if we're showing any status
      window.showedBuilder = window.showedBuilder || (
        statusElement !== null || (status && status !== 'none')
      )
      if (window.showedBuilder) clearInterval(window.checkInterval)
    }, 50)
  })()`)
}

describe('GS(S)P Server-Side Change Reloading', () => {
  const { next } = nextTestSetup({

er = await next.browser('/gsp-blog/first')
    await check(() => browser.elementByCss('#change').text(), 'change me')
    await browser.eval(`window.beforeChange = 'hi'`)

    const props = JSON.parse(await browser.elementByCss('#props').text())

    const

    files: {
      pages: new FileRef(join(__dirname, '../pages')),
      lib: new FileRef(join(__dirname, '../lib')),
    },
  })

  it('should not reload page when client-side is changed too GSP', async () => {
    const brows


    </body>
    </Html>
  )
}

Document.getInitialProps = (ctx) => {
  return ctx.defaultGetInitialProps(ctx)
}
`

const basePath = process.env.TEST_BASE_PATH || ''
const srcPrefix = process.env.TEST_SRC_DIR ? 'src/' : ''

describe('next/dynamic', () => {
  const { next } = nextTestSetup({
    files: {
      [`${srcPrefix}/components`]: new FileRef(join(__dirname, 'components')),
      [`${srcPrefix}/pages`]: new FileRef(join(__dirname, 'pages')),
      ...(process.env.TEST_CUSTOMIZED_DOCUMENT === '1' && {

BABEL === '1' && {
          '.babelrc': `{ "presets": ["next/babel"] }`,
        }),
    },
    nextConfig: {
      basePath,
    },
  })

  async function get$(path, query?: any) {
    const html = await renderViaHTTP(next.url, path, query)
    return ch

        [`${srcPrefix}/pages/_document.js`]: customDocumentGipContent,
      }),
      // When it's not turbopack and babel is enabled, we add a .babelrc file.
      ...(!process.env.IS_TURBOPACK_TEST &&
        process.env.TEST_