v jest */

import { getFilesInDir } from 'next/dist/lib/get-files-in-dir'
import { join } from 'path'
import fs from 'fs-extra'

const testDir = join(__dirname, 'get-files-in-dir-test')

const srcDir = join(testDir, 'src')

const setupTestDir = async () => {
  const paths = [
    '.hidden',
    'file',
    'folder1/file1',
    'folder1/file2',
    'link',
    'linkfolder',
  ]

  await fs.ensureDir(testDir)

  // create src directory structure
  await fs.ensureDir(srcDir)
  await fs.outputFile(join(srcDir,

join(srcDir, 'file'), join(srcDir, 'link'))
  await fs.ensureSymlink(join(srcDir, 'link'), join(srcDir, 'link-level-2'))
  await fs.ensureSymlink(
    join(srcDir, 'link-level-2'),
    join(srcDir, 'link-level-3')
  )
  await fs.ensureSymlink(join(srcDir,

'.hidden'), 'hidden')
  await fs.outputFile(join(srcDir, 'file'), 'file')
  await fs.outputFile(join(srcDir, 'folder1', 'file1'), 'file1')
  await fs.outputFile(join(srcDir, 'folder1', 'file2'), 'file2')
  await fs.ensureSymlink(


nv jest */
import { Component } from 'react'
import { getDisplayName } from 'next/dist/shared/lib/utils'

describe('getDisplayName', () => {
  it('gets the proper display name of a component', () => {
    class ComponentOne extends Component {
      render() {
        return null
      }
    }

    class ComponentTwo extends Component {
      static displayName = 'CustomDisplayName'
      render() {
        return null
      }
    }

    function FunctionalComponent() {
      return null
    }

    expect(g

  expect(getDisplayName(ComponentTwo)).toBe('CustomDisplayName')
    expect(getDisplayName(FunctionalComponent)).toBe('FunctionalComponent')
    expect(getDisplayName(() => null)).toBe('Unknown')
    expect(getDisplayName('div' as any)).toBe('div')
  })
})


These tests are based on https://github.com/zertosh/htmlescape/blob/3e6cf0614dd0f778fd0131e69070b77282150c15/test/htmlescape-test.js
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
import { htmlEscapeJsonString } from 'next/dist/shared/lib/htmlescape'
import vm from 'vm'

describe('htmlescape', () => {
  test('with angle brackets should escape', () => {
    const evilObj = { evil: '<script></script>' }
    expect(htmlEscapeJsonString(JSON.stringify(evi

apeJsonString(JSON.stringify(evilObj)))
    ).toMatchObject(evilObj)
  })

  test('with ampersands should escape', () => {
    const evilObj = { evil: '&' }
    expect(htmlEscapeJsonString(JSON.stringify(evilObj))).toBe(
      '{"evil":"\\u0026"}'
    )

lObj))).toBe(
      '{"evil":"\\u003cscript\\u003e\\u003c/script\\u003e"}'
    )
  })

  test('with angle brackets should parse back', () => {
    const evilObj = { evil: '<script></script>' }
    expect(
      JSON.parse(htmlEsc


v jest */
import { ImageResponse } from 'next/og'
import React from 'react'

describe('new ImageResponse()', () => {
  const exactHeader = 'public, max-age=3600, s-maxage=3600'
  it('should merge object literal headers correctly', () => {
    const res = new ImageResponse(
      React.createElement(
        'div',
        { style: { width: 10, height: 10 } },
        'ImageResponse'
      ),
      {
        width: 10,
        height: 10,
        headers: {
          'Cache-Control': exactHeader,
        },

      React.createElement(
        'div',
        { style: { width: 10, height: 10 } },
        'ImageResponse'
      ),
      {
        width: 10,
        height: 10,
        headers: new Headers({
          'Cache-Control': exactHeader,
        }),

      }
    )
    expect(res.headers.get('Content-Type')).toBeTruthy()
    expect(res.headers.get('Cache-Control')).toBe(exactHeader)
  })
  it('should merge Headers instance correctly', () => {
    const res = new ImageResponse(


erverSidePropsType,
  GetServerSidePropsContext,
} from 'next'
import { expectTypeOf } from 'expect-type'

describe('InferGetServerSidePropsType', () => {
  it('should work with sync functions', async () => {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    function getServerSideProps(context: GetServerSidePropsContext) {
      if (context.params?.notFound) {
        return {
          notFound: true,
        }
      }

      return {
        props: {
          foo: 'bar',
        },

isable-next-line @typescript-eslint/no-unused-vars
    async function getServerSideProps(context: GetServerSidePropsContext) {
      if (context.params?.notFound) {
        return {
          notFound: true,
        }
      }

      if (context.params?.red

    }
    }

    type PageProps = InferGetServerSidePropsType<typeof getServerSideProps>

    expectTypeOf<PageProps>().toEqualTypeOf<{ foo: string }>()
  })

  it('should work with async functions', async () => {
    // eslint-d


{ InferGetStaticPropsType, GetStaticPropsContext } from 'next'
import { expectTypeOf } from 'expect-type'

describe('InferGetServerSidePropsType', () => {
  it('should work with sync functions', async () => {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    function getStaticProps(context: GetStaticPropsContext) {
      if (context.params?.notFound) {
        return {
          notFound: true,
        }
      }

      return {
        props: {
          foo: 'bar',
        },
      }

 @typescript-eslint/no-unused-vars
    async function getStaticProps(context: GetStaticPropsContext) {
      if (context.params?.notFound) {
        return {
          notFound: true,
        }
      }

      if (context.params?.redirect) {
        return

  }

    type PageProps = InferGetStaticPropsType<typeof getStaticProps>

    expectTypeOf<PageProps>().toEqualTypeOf<{ foo: string }>()
  })

  it('should work with async functions', async () => {
    // eslint-disable-next-line


t/dist/server/config'
import { PHASE_PRODUCTION_SERVER } from 'next/constants'

// `loadConfig` caches its result keyed on `dir` + a boolean "hasCustomConfig".
// Each test uses a unique subdirectory so the cache doesn't bleed between
// cases. The subdirectory doesn't need to exist — only the string matters
// for the cache key, and `loadEnvConfig` tolerates missing dirs.
function uniqueDir(tag: string) {
  return path.join(__dirname, `__instant_normalization_${tag}__`)
}

// Covers the `finalizeConfig` st

onLevel normalization', () => {
  it('defaults to manual-warning when the instantInsights config is absent', async () => {
    const config = await loadConfig(
      PHASE_PRODUCTION_SERVER,
      uniqueDir('absent'),
      {
        customConfig: {},

ep in loadConfig: resolving
// `experimental.instantInsights.validationLevel` to a concrete value in
// one place so consumers don't each need to know the current framework default.
describe('experimental.instantInsights validati


jsdom
 */
/* eslint-env jest */
import { isEqualNode } from 'next/dist/client/head-manager'

const createScriptElement = (attrs = {}) => {
  const el = document.createElement('script')
  for (const k in attrs) el.setAttribute(k, attrs[k])
  return el
}

describe('isEqualNode', () => {
  it('should equal itself', () => {
    const el = createScriptElement()
    expect(isEqualNode(el, el)).toBe(true)
  })

  it('should equal equivalent node that has no nonce', () => {
    const el1 = createScriptElement()

t el1 = createScriptElement({ nonce: 'abc123' })
    // Simulate Chrome/FF browser behavior of stripping off nonce value when adding element to the document
    el1.setAttribute('nonce', '')
    el1.nonce = 'abc123'
    const el2 = createScriptElement({ no

 const el2 = createScriptElement()
    expect(isEqualNode(el1, el2)).toBe(true)
  })

  it('should equal equivalent node that has same nonce property, even if the original node has no html nonce attribute value', () => {
    cons


test: \`{ props: { ... } }\` (received: \`[object Null]\`)."
    `)

    expect(() => isSerializableProps('/', 'test', undefined))
      .toThrowErrorMatchingInlineSnapshot(`
      "Error serializing props returned from \`test\` in "/".
      Reason: Props must be returned as a plain object from test: \`{ props: { ... } }\` (received: \`[object Undefined]\`)."
    `)
  })

  it('handles non-plain object props', () => {
    expect(() => isSerializableProps('/', 'test', []))
      .toThrowErrorMatchingInlineS

ableProps('/', 'test', class Foobar {}))
      .toThrowErrorMatchingInlineSnapshot(`
      "Error serializing props returned from \`test\` in "/".
      Reason: Props must be returned as a plain object from test: \`{ props: { ... } }\` (received: \`[object

napshot(`
      "Error serializing props returned from \`test\` in "/".
      Reason: Props must be returned as a plain object from test: \`{ props: { ... } }\` (received: \`[object Array]\`)."
    `)

    expect(() => isSerializ


st-environment jsdom
 */
import { act, render } from '@testing-library/react'
import '@testing-library/jest-dom'
import Link from 'next/link'
import React from 'react'

describe('<Link/>', () => {
  let spy
  let expectedErrors
  beforeAll(async () => {
    spy = jest.spyOn(console, 'error').mockImplementation((...args) => {
      console.log(...args)
    })

    expectedErrors = 0
  })

  it('test link with unmount', () => {
    act(() => {
      const { unmount } = render(<Link href="/">hello</Link>)

  })

    expect(spy).toHaveBeenCalledTimes(expectedErrors)
  })

  it('test link without unmount', () => {
    act(() => {
      render(<Link href="/">hello</Link>)
    })

    expect(spy).toHaveBeenCalledTimes(expectedErrors)
  })

  afterAll(() => {


ort { loadGetInitialProps } from 'next/dist/shared/lib/utils'

describe('loadGetInitialProps', () => {
  it('should throw if getInitialProps is defined as an instance method', () => {
    class TestComponent {
      getInitialProps() {}
    }
    const rejectPromise = loadGetInitialProps(TestComponent as any, {})
    const error = new Error(
      '"TestComponent.getInitialProps()" is defined as an instance method - visit https://nextjs.org/docs/messages/get-initial-props-as-an-instance-method for more info

})
    expect(result).toEqual({})
  })

  it('should resolve getInitialProps', async () => {
    class TestComponent {
      static async getInitialProps() {
        return { foo: 1 }
      }
    }
    const result = await loadGetInitialProps(TestComponent

rmation.'
    )
    return expect(rejectPromise).rejects.toEqual(error)
  })

  it('should resolve to an empty object if getInitialProps is missing', async () => {
    const result = await loadGetInitialProps((() => {}) as any, {


vedMetadata properties can be assigned to
 * Metadata input types. This is important because users often want to
 * extend parent metadata in generateMetadata:
 *
 * ```ts
 * export async function generateMetadata(_, parent: ResolvingMetadata) {
 *   const resolved = await parent
 *   return {
 *     openGraph: {
 *       ...resolved.openGraph,  // Should not cause type errors
 *       title: 'Override title',
 *     },
 *   }
 * }
 * ```
 *
 * If these tests fail, it means ResolvedMetadata has properties

esolvedOpenGraphUrl = NonNullable<ResolvedMetadata['openGraph']>['url']
type MetadataOpenGraphUrl = NonNullable<Metadata['openGraph']>['url']

type ResolvedTwitterSite = NonNullable<ResolvedMetadata['twitter']>['site']
type MetadataTwitterSite = NonNullabl

* that are not assignable to Metadata (e.g., `null` vs `undefined` mismatch).
 */

import type { Metadata, ResolvedMetadata } from 'next'
import { expectTypeOf } from 'expect-type'

// Extract property types for comparison
type R


ort mitt from 'next/dist/shared/lib/mitt'

describe('mitt', () => {
  describe('With listeners', () => {
    it('should listen to an event', () => {
      return new Promise((resolve) => {
        const ev = mitt()
        ev.on('sample', resolve)
        ev.emit('sample')
      })
    })

    it('should listen to multiple listeners', () => {
      const ev = mitt()
      let cnt = 0

      ev.on('sample', () => {
        cnt += 1
      })
      ev.on('sample', () => {
        cnt += 1
      })

      ev.em

 cb)
      ev.on('sample2', cb)

      ev.emit('sample1', 'one')
      ev.emit('sample2', 'two')

      expect(data).toEqual(['one', 'two'])
    })

    it('should support multiple arguments', () => {
      const ev = mitt()
      let data

      ev.on('sa

it('sample')

      expect(cnt).toBe(2)
    })

    it('should listen to multiple events', () => {
      const ev = mitt()
      const data = []
      const cb = (name) => {
        data.push(name)
      }

      ev.on('sample1',


e'
import loader from 'next/dist/build/babel/loader'

const dir = path.resolve(os.tmpdir())

const babel = async (code: string, queryOpts = {} as any) => {
  const { isServer = false, resourcePath = `index.js` } = queryOpts

  let isAsync = false

  const options = {
    // loader opts
    cwd: dir,
    isServer,
    distDir: path.resolve(dir, '.next'),
    pagesDir:
      'pagesDir' in queryOpts ? queryOpts.pagesDir : path.resolve(dir, 'pages'),
    cache: false,
    development: true,
    hasReactRefresh:

))
      }
    }

    const res = loader.bind({
      resourcePath,
      async() {
        isAsync = true
        return callback
      },
      callback,
      emitWarning() {},
      query: options,
      getOptions: function () {
        return options

 !isServer,
    transformMode: 'default',
  }
  return new Promise<string>((resolve, reject) => {
    function callback(err, content) {
      if (err) {
        reject(err)
      } else {
        resolve(content.replace(/\n/g, ''


tion callback(err, content) {
      if (err) {
        reject(err)
      } else {
        resolve(content.replace(/\n/g, ''))
      }
    }

    const options = {
      // loader opts
      cwd: dir,
      isServer,
      distDir: path.resolve(dir, '.next'),
      pagesDir:
        'pagesDir' in queryOpts
          ? queryOpts.pagesDir
          : path.resolve(dir, 'pages'),
      cache: false,
      hasReactRefresh: false,
      transformMode: 'default',
    }

    const res = loader.bind({
      resourceP

w Span({ name: 'test' }),
    })(code, null)

    if (!isAsync) {
      resolve(res)
    }
  })
}

describe('next-babel-loader', () => {
  describe('replace constants', () => {
    it('should replace typeof window expression nested', async () => {
      co

ath,
      async() {
        isAsync = true
        return callback
      },
      callback,
      emitWarning() {},
      query: options,
      getOptions: function () {
        return options
      },
      currentTraceSpan: ne


) =>
  transformSync(code, {
    filename,
    presets: [[require('next/dist/build/babel/preset'), presetOptions]],
    babelrc: false,
    configFile: false,
    sourceType: 'module',
    compact: true,
    caller: {
      name: 'tests',
      supportsStaticESM: esm,
      isDev: false,
    },
  } as any).code

describe('next/babel', () => {
  describe('jsx-pragma', () => {
    it('should transform JSX to use a local identifier in modern mode', () => {
      const output = babel(`const a = () => <a href="/

reateElement`)
      // it should use that factory for all JSX:
      expect(output).toMatch(`__jsx("a",{href:"/"`)

      expect(
        babel(`const a = ()=><a href="/">home</a>`, true)
      ).toMatchInlineSnapshot(
        `"import React from"react";v

">home</a>;`, true)

      // it should add a React import:
      expect(output).toMatch(`import React from"react"`)
      // it should hoist JSX factory to a module level variable:
      expect(output).toMatch(`var __jsx=React.c


', '/_next/image?url=%2Ftest.png&w=256&q=75'],
    ])
  })

  it('should have correct type for props', async () => {
    const { props } = getImageProps({
      alt: 'a nice desc',
      id: 'my-image',
      src: '/test.png',
      width: 100,
      height: 200,
    })

    expect(props.alt).toBeString()
    expect(props.id).toBeString()
    expect(props.loading).toBeString()

    expect(props.width).toBeNumber()
    expect(props.height).toBeNumber()

    expect(props.decoding).toBeString()
    expect(prop

   alt: 'a nice desc',
      id: 'my-image',
      src: '/test.png',
      width: 100,
      height: 200,
      preload: true,
    })
    expect(warningMessages).toStrictEqual([])
    expect(Object.entries(props)).toStrictEqual([
      ['alt', 'a nice desc

s.style).toBeObject()
    expect(props.style.color).toBeString()
    expect(props.src).toBeString()
    expect(props.srcSet).toBeString()
  })

  it('should handle preload', async () => {
    const { props } = getImageProps({


'next/dist/shared/lib/deployment-id.js', () => {
  return {
    __esModule: true,
    getDeploymentId() {
      return deploymentId
    },
    getDeploymentIdQuery(ampersand = false): string {
      let id = deploymentId
      if (id) {
        return `${ampersand ? '&' : '?'}dpl=${id}`
      }
      return ''
    },
    getAssetToken() {
      throw new Error("getAssetToken shouldn't be called ")
    },
    getAssetTokenQuery(ampersand = false) {
      throw new Error("getAssetTokenQuery shouldn't be calle

,
      height: 100,
      loading: 'eager',
    })
    const html = ReactDOM.renderToString(element)
    const $ = cheerio.load(html)
    const img = $('#unit-image')
    expect(img.attr('id')).toBe('unit-image')
    expect(img.attr('src')).toContain('tes

d ")
    },
  }
})

describe('Image Legacy Rendering', () => {
  it('should render Image on its own', async () => {
    const element = React.createElement(Image, {
      id: 'unit-image',
      src: '/test.png',
      width: 100


ort ReactDOMServer from 'react-dom/server'
import Image from 'next/image'
import cheerio from 'cheerio'

describe('Image rendering', () => {
  it('should render Image on its own', async () => {
    const element = React.createElement(Image, {
      alt: 'a nice image',
      id: 'unit-image',
      src: '/test.png',
      width: 100,
      height: 100,
      loading: 'eager',
    })
    const html = ReactDOMServer.renderToString(element)
    const $ = cheerio.load(html)
    const img = $('#unit-image')

   style: 'color:transparent',
      srcset:
        '/_next/image?url=%2Ftest.png&w=128&q=75 1x, /_next/image?url=%2Ftest.png&w=256&q=75 2x',
      src: '/_next/image?url=%2Ftest.png&w=256&q=75',
    })
  })

  it('should only render noscript element when

// order matters here
    expect(img.attr()).toStrictEqual({
      alt: 'a nice image',
      id: 'unit-image',
      loading: 'eager',
      width: '100',
      height: '100',
      decoding: 'async',
      'data-nimg': '1',


c = async (code) => {
  let output = await transform(code)
  return output.code
}

const trim = (s) => s.join('\n').trim().replace(/^\s+/gm, '')

describe('next/swc', () => {
  beforeAll(async () => {
    await installBindings()
  })
  describe('hook_optimizer', () => {
    it('should leave alone array destructuring of hooks', async () => {
      const output = await swc(
        trim`
        import { useState } from 'react';
        const [count, setCount] = useState(0);
      `
      )

      expect(outp

          return arr2;
        }
        function _array_with_holes(arr) {
            if (Array.isArray(arr)) return arr;
        }
        function _iterable_to_array_limit(arr, i) {
            var _i = arr == null ? null : typeof Symbol !== "undefined"

ut).toMatchInlineSnapshot(`
        "function _array_like_to_array(arr, len) {
            if (len == null || len > arr.length) len = arr.length;
            for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];


/* eslint-env jest */
import { getOxfordCommaList } from 'next/dist/lib/oxford-comma-list'

describe('oxford-comma-list', () => {
  test('empty array', () => {
    expect(getOxfordCommaList([])).toMatchInlineSnapshot(`""`)
  })

  test('single item array', () => {
    expect(getOxfordCommaList(['apples'])).toMatchInlineSnapshot(`"apples"`)
  })

  test('two item array', () => {
    expect(
      getOxfordCommaList(['apples', 'strawberries'])
    ).toMatchInlineSnapshot(`"apples and strawberries"`)
  })

  t

pect(getOxfordCommaList(['1', '2', '3', '4'])).toMatchInlineSnapshot(
      `"1, 2, 3, and 4"`
    )
  })

  test('five item array', () => {
    expect(getOxfordCommaList(['1', '2', '3', '4', '5'])).toMatchInlineSnapshot(
      `"1, 2, 3, 4, and 5"`
    )

est('three item array', () => {
    expect(
      getOxfordCommaList(['apples', 'strawberries', 'blueberries'])
    ).toMatchInlineSnapshot(`"apples, strawberries, and blueberries"`)
  })

  test('four item array', () => {
    ex


outes(['/posts'])).toEqual(['/posts'])

    expect(getSortedRoutes(['/posts/[id]'])).toEqual(['/posts/[id]'])
    expect(getSortedRoutes(['/posts/[id]/foo'])).toEqual(['/posts/[id]/foo'])

    expect(getSortedRoutes(['/posts/[id]/[foo]/bar'])).toEqual([
      '/posts/[id]/[foo]/bar',
    ])
    expect(getSortedRoutes(['/posts/[id]/baz/[foo]/bar'])).toEqual([
      '/posts/[id]/baz/[foo]/bar',
    ])
  })

  it('correctly sorts required slugs', () => {
    expect(
      getSortedRoutes([
        '/posts',


uild/analysis/get-page-static-info'
import { installBindings } from 'next/dist/build/swc/install-bindings'
import { PAGE_TYPES } from 'next/dist/lib/page-types'
import { join } from 'path'

const fixtureDir = join(__dirname, 'fixtures')

function createNextConfig() {
  return {}
}

describe('parse page static info', () => {
  beforeAll(async () => {
    await installBindings()
  })
  it('should parse nodejs runtime correctly', async () => {
    const { runtime, getServerSideProps, getStaticProps } =
      a

   })
    expect(runtime).toBe('nodejs')
    expect(getServerSideProps).toBe(true)
    expect(getStaticProps).toBe(false)
  })

  it('should parse static runtime correctly', async () => {
    const { runtime, getServerSideProps, getStaticProps } =
      aw

wait getPagesPageStaticInfo({
        page: 'nodejs-ssr',
        pageFilePath: join(fixtureDir, 'page-runtime/nodejs-ssr.js'),
        nextConfig: createNextConfig(),
        pageType: PAGE_TYPES.PAGES,
        isDev: false,


ve-url'

// convenience function so tests can be aligned neatly
// and easy to eyeball
const check = (windowUrl, targetUrl, expected) => {
  window.location = new URL(windowUrl) as any
  if (typeof expected === 'string') {
    expect(() => parseRelativeUrl(targetUrl)).toThrow(expected)
  } else {
    const parsedUrl = parseRelativeUrl(targetUrl)
    expect(parsedUrl.pathname).toBe(expected.pathname)
    expect(parsedUrl.search).toBe(expected.search)
    expect(parsedUrl.hash).toBe(expected.hash)
  }
}

desc

      'http://example.com:3210/someA/pathB?fooC=barD#hashE',
      '/someF/pathG?fooH=barI#hashJ',
      {
        pathname: '/someF/pathG',
        search: '?fooH=barI',
        hash: '#hashJ',
      }
    )
  })

  it('should parse relative url when star

ribe('parseRelativeUrl', () => {
  beforeAll(() => {
    ;(global as any).window = {
      location: {},
    }
  })

  afterAll(() => {
    delete (global as any).window
  })

  it('should parse relative url', () => {
    check(


m 'next/dist/lib/recursive-copy'
import { join } from 'path'
import fs from 'fs-extra'
import { readFileSync } from 'fs'

const testDir = join(__dirname, 'recursive-folder-test')

const srcDir = join(testDir, 'src')
const destDir = join(testDir, 'dest')

const setupTestDir = async (numFiles = 100) => {
  const paths = [
    '.hidden',
    'file',
    'folder1/file1',
    'folder1/file2',
    'link',
    'linkfolder',
  ]

  await fs.ensureDir(testDir)

  // create src directory structure
  await fs.ensureDi

 'file2'), 'file2')
  await fs.ensureSymlink(join(srcDir, 'file'), join(srcDir, 'link'))
  await fs.ensureSymlink(join(srcDir, 'folder1'), join(srcDir, 'linkfolder'))

  for (let i = 0; i < numFiles - 6; i++) {
    const path = join(`folder-${i}`, `file-${

r(srcDir)
  await fs.outputFile(join(srcDir, '.hidden'), 'hidden')
  await fs.outputFile(join(srcDir, 'file'), 'file')
  await fs.outputFile(join(srcDir, 'folder1', 'file1'), 'file1')
  await fs.outputFile(join(srcDir, 'folder1',


ort {
  recursiveDeleteSyncWithAsyncRetries,
  calcBackoffMs,
} from 'next/dist/lib/recursive-delete'
import { recursiveReadDir } from 'next/dist/lib/recursive-readdir'
import { recursiveCopy } from 'next/dist/lib/recursive-copy'
import { join } from 'path'

const resolveDataDir = join(__dirname, 'isolated', '_resolvedata')
const testResolveDataDir = join(__dirname, 'isolated', 'test_resolvedata')
const testpreservefileDir = join(__dirname, 'isolated', 'preservefiles')

describe('recursiveDeleteSyncWithAsyn

eCopy(resolveDataDir, testResolveDataDir)
      await fs.symlink('./aa', join(testResolveDataDir, 'symlink'))
      await recursiveDeleteSyncWithAsyncRetries(testResolveDataDir)
      const result = await recursiveReadDir(testResolveDataDir)
      expect(r

cRetries', () => {
  if (process.platform === 'win32') {
    it('should skip on windows to avoid symlink issues', () => {})
    return
  }

  it('should work', async () => {
    expect.assertions(1)
    try {
      await recursiv


rt { join } from 'path'

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

describe('recursiveReadDir', () => {
  it('should work', async () => {
    const result = await recursiveReadDir(dirWithPages, {
      pathnameFilter: (f) => /\.js/.test(f),
    })
    const pages = [
      /^[\\/]index\.js/,
      /^[\\/]prefered\.js/,
      /^[\\/]nav[\\/]about\.js/,
      /^[\\/]nav[\\/]index\.js/,
      /^[\\/]nested[\\/]index\.js/,

v[\\/]products[\\/]product\.js/,
    ]
    expect(
      result.filter((item) => {
        for (const page of pages) {
          if (page.test(item)) {
            return false
          }
        }

        return true
      }).length
    ).toBe(0)
  })
}


ver/web/utils'
import cookie from 'next/dist/compiled/cookie'

function generateCookies(
  ...cookieOptions: (CookieSerializeOptions & { name: string; value: string })[]
) {
  const cookies = cookieOptions.map((opts) =>
    cookie.serialize(opts.name, opts.value, opts)
  )
  return {
    joined: cookies.join(', '),
    expected: cookies,
  }
}

describe('splitCookiesString', () => {
  describe('with a single cookie', () => {
    it('should parse a plain value', () => {
      const { joined, expected } = gen

ed } = generateCookies({
        name: 'foo',
        value: 'bar',
        expires: new Date(),
      })
      const result = splitCookiesString(joined)
      expect(result).toEqual(expected)
    })

    it('should parse max-age', () => {
      const { jo

erateCookies({
        name: 'foo',
        value: 'bar',
      })
      const result = splitCookiesString(joined)
      expect(result).toEqual(expected)
    })

    it('should parse expires', () => {
      const { joined, expect


d/swc/options'

describe('swcEnvOptions', () => {
  const baseArgs = {
    filename: '/app/page.tsx',
    development: false,
    isServer: false,
    pagesDir: '/pages',
    appDir: '/app',
    isPageFile: false,
    hasReactRefresh: false,
    modularizeImports: undefined,
    swcPlugins: undefined,
    compilerOptions: undefined,
    jsConfig: {},
    swcCacheDir: '/tmp/swc',
    relativeFilePathFromRoot: 'app/page.tsx',
    serverComponents: false,
    serverReferenceHashSalt: 'test-salt',
    bundleLay

Browsers: ['chrome 80'],
    })
    expect(options.env).toEqual({ targets: ['chrome 80'] })
  })

  it('should include mode and coreJs when configured', () => {
    const options = getLoaderSWCOptions({
      ...baseArgs,
      supportedBrowsers: ['chrome

er: undefined,
    cacheHandlers: undefined,
    configDir: '/',
  }

  it('should not include extra env options when swcEnvOptions is not set', () => {
    const options = getLoaderSWCOptions({
      ...baseArgs,
      supported


import { nextTestSetup } from 'e2e-utils'

describe('next-image-legacy-src-with-query-without-local-patterns', () => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    skipStart: true,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  it('should throw error for relative image with query without localPatterns for legacy Image', async () => {
    if (isNextDev) {
      await next.start()
      await next.browser('/')
      expect(next.cliOutput).toContain(

liOutput } = await next.build()
      expect(cliOutput).toContain(
        'Image with src "/test.png?v=1" is using a query string which is not configured in images.localPatterns.\nRead more: https://nextjs.org/docs/messages/next-image-unconfigured-localpa

    'Image with src "/test.png?v=1" is using a query string which is not configured in images.localPatterns.\nRead more: https://nextjs.org/docs/messages/next-image-unconfigured-localpatterns'
      )
    } else {
      const { c


tion getUnsupportedModuleWarning(name: string) {
  return `A Node.js module is loaded ('${name}'`
}

function escapeLF(s: string) {
  return s.replace(/\n/g, '\\n')
}

function expectUnsupportedModuleProdError(moduleName: string, output: string) {
  const moduleNotSupportedMessage = getUnsupportedModule(moduleName)
  expect(output).toContain(moduleNotSupportedMessage)
  const moduleNotFoundMessage = getModuleNotFound(moduleName)
  expect(output).not.toContain(moduleNotFoundMessage)
}

function expectUnsuppo

2e (isolated app).
  // TODO: Uncomment once codeframe is verified to point to user code
  // expect(stripAnsi(output)).toContain(importStatement)

  const moduleNotSupportedMessage = getUnsupportedModule(moduleName)
  expect(responseText).toContain(escape

rtedModuleDevError(
  moduleName: string,
  _importStatement: string,
  responseText: string,
  output: string
) {
  expectUnsupportedModuleProdError(moduleName, output)
  // Codeframe should now include the import statement in e


ith src folder',
      appDir: 'app-with-src',
      shouldLog: false,
    },
    {
      name: 'App Router',
      appDir: 'app-router',
      shouldLog: true,
    },
    {
      name: 'Pages Router',
      appDir: 'pages-router',
      shouldLog: false,
    },
  ])('$name', ({ name, appDir, shouldLog }) => {
    describe(name, () => {
      const { next, isNextDev } = nextTestSetup({
        files: path.join(__dirname, appDir),
      })

      it(`should execute instrumentation-client from ${name.toLowerC

ationTime = await browser.eval(`window.__NEXT_HYDRATED_AT`)

        expect(instrumentationTime).toBeDefined()
        expect(hydrationTime).toBeDefined()
        expect(instrumentationTime).toBeLessThan(hydrationTime)
        expect(
          (await brow

ase()} before hydration`, async () => {
        const browser = await next.browser('/')

        const instrumentationTime = await browser.eval(
          `window.__INSTRUMENTATION_CLIENT_EXECUTED_AT`
        )
        const hydr


 'path'

describe('cache-handlers-upstream-wiring', () => {
  describe('pages router non-edge', () => {
    const { next, skipped, isNextDev } = nextTestSetup({
      files: join(__dirname, 'fixtures/pages-router-non-edge'),
      skipDeployment: true,
    })

    if (skipped) {
      return
    }

    let outputIndex = 0

    beforeEach(() => {
      outputIndex = next.cliOutput.length
    })

    it('wires res.revalidate() through the configured custom cacheHandler', async () => {
      const initialHtml

atus).toBe(200)
      expect(await revalidateResponse.json()).toEqual({ revalidated: true })

      if (!isNextDev) {
        await retry(async () => {
          const htmlAfterRevalidate = await next.render$('/isr')
          const valueAfterRevalidate =

= await next.render$('/isr')
      const initialValue = initialHtml('#now').text()
      outputIndex = next.cliOutput.length

      const revalidateResponse = await next.fetch('/api/revalidate')
      expect(revalidateResponse.st


etup } from 'e2e-utils'

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

  const { next } = nextTestSetup({
    files: new FileRef(path.join(__dirname, './npm')),
    dependencies: {
      sass: 'latest',
    },
  })

  const { isNextDeploy } = global as any
  if (isNextDeploy) {
    it('should skip tests for next-deploy and react 17', () => {})
    return
  }

  // TODO: This test is failing in Turbopack

uld handle global css imports inside transpiled modules', async () => {
      const browser = await next.browser('/global-css')

      expect(
        await browser.eval(
          `window.getComputedStyle(document.querySelector('body')).backgroundColor`

it.skip('should handle optional peer dependencies', async () => {
    const browser = await next.browser('/peer-deps')

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

  describe('css', () => {
    it('sho


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

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

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

    it('navigates correctly', async () => {
      const browser = await next.browser('/')
      await browser.elementByCss('a').click()
      co

   await browser.elementByCss('a').click()
    const title = await browser.elementByCss('h1').text()

    expect(title).toBe('About Page')
  })

  it('works if the child is a string', async () => {
    const browser = await next.browser('/child-is-a-string

nst title = await browser.elementByCss('#about-page').text()

      expect(title).toBe('About Page')
    })
  })

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


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

const strictRouteTypes =
  process.env.__NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES === 'true'

describe('tsconfig module: preserve', () => {
  const { next, skipped } = nextTestSetup({
    files: {
      'tsconfig.json': JSON.stringify({
        compilerOptions: { module: 'preserve' },
      }),
      'pages/index.tsx': `
        export default function Page() {
          return
hello world

        }
      `,
    },
    // This test is s

dule when using "module: preserve"', async () => {
    let output = ''

    await retry(() => {
      output = stripAnsi(next.cliOutput)
      expect(output).toContain(
        'The following mandatory changes were made to your tsconfig.json'
      )
    }

kipped because it relies on `next.readFile`
    skipDeployment: true,
    dependencies: {
      typescript: '5.4.4',
    },
  })

  if (skipped) return

  it('allows you to skip moduleResolution, esModuleInterop and resolveJsonMo


from 'path'
import os from 'os'
import {
  throwTurbopackInternalError,
  TurbopackInternalError,
} from 'next/dist/shared/lib/turbopack/internal-error'
import { Telemetry } from 'next/dist/telemetry/storage'
import { setGlobal } from 'next/dist/trace'
import { traceGlobals } from 'next/dist/trace/shared'

describe('TurbopackInternalError', () => {
  it('sends a telemetry event when throwTurbopackInternalError() is called', async () => {
    const oldTelemetry = traceGlobals.get('telemetry')

    try {

 'submitRecord')
        // @ts-ignore
        .mockImplementation(() => Promise.resolve())

      let internalError = null
      try {
        throwTurbopackInternalError(null, {
          message: 'test error',
          anonymizedLocation: 'file.rs:120:

  const distDir = path.join(os.tmpdir(), 'next-telemetry')
      const telemetry = new Telemetry({ distDir })
      setGlobal('telemetry', telemetry)
      const submitRecord = jest
        // @ts-ignore
        .spyOn(telemetry,


cept-header'

describe('acceptLanguage', () => {
  it('parses the header', () => {
    const language = acceptLanguage('da, en-GB, en')
    expect(language).toEqual('da')
  })

  it('respects weights', () => {
    const language = acceptLanguage('en;q=0.6, en-GB;q=0.8')
    expect(language).toEqual('en-gb')
  })

  it('returns an empty string with header is empty', () => {
    const language = acceptLanguage('')
    expect(language).toEqual('')
  })

  it('returns empty string if header is missing', () => {

it('returns empty string if none of the preferences match', () => {
    const language = acceptLanguage('da, en-GB, en', ['es'])
    expect(language).toEqual('')
  })

  it('returns first preference if header has * and is unmatched', () => {
    const lang

    const language = acceptLanguage()
    expect(language).toEqual('')
  })

  it('ignores an empty preferences array', () => {
    const language = acceptLanguage('da, en-GB, en', [])
    expect(language).toEqual('da')
  })


t { warnOnce } from 'next/dist/build/output/log'

describe('build/output/log', () => {
  it('warnOnce', () => {
    const original = console.warn
    try {
      const messages = []
      console.warn = (m: any) => messages.push(m)
      warnOnce('test')
      expect(messages.length).toEqual(1)
      warnOnce('test again')
      expect(messages.length).toEqual(2)
      warnOnce('test', 'more')
      expect(messages.length).toEqual(3)
      warnOnce('test')
      expect(messages.length).toEqual(3)
      warn

in')
      expect(messages.length).toEqual(3)
      warnOnce('test', 'more')
      expect(messages.length).toEqual(3)
      warnOnce('test', 'should', 'add', 'another')
      expect(messages.length).toEqual(4)
    } finally {
      console.warn = original


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

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

  it(`should place charset element at the top of <head>`, async () => {
    const browser = await next.browser('/')

    const html = await browser.eval(() => {

a name="test-head-1" content="hello" data-next-head="">`
    )
  })

  it('should have correct head tags in initial document', async () => {
    const html = await renderViaHTTP(next.url, '/')
    const $ = cheerio.load(html)

    for (let i = 1; i < 5; i+

 const head = document.querySelector('head')
      return head.innerHTML
    })

    expect(html).toContain(
      `<meta charset="utf-8" data-next-head=""><meta name="viewport" content="width=device-width" data-next-head=""><met


ts = {
  onBuildComplete({ outputs }) {
    const pagesDataPathnames = outputs.pages
      .map((item) => item.pathname)
      .filter((item) => item.startsWith('/_next/data/'))
    const appPagesDataPathnames = outputs.appPages
      .map((item) => item.pathname)
      .filter((item) => item.startsWith('/_next/data/'))

    const hasIndexData = pagesDataPathnames.some((item) =>
      /^\/_next\/data\/[^/]+\/index\.json$/.test(item)
    )
    const hasDynamicData = pagesDataPathnames.some((item) =>
      /^

  if (!hasIndexData || !hasDynamicData || hasDoubleIndexData) {
      throw new Error(
        [
          'Unexpected edge pages data output from adapter build:',
          `pagesDataPathnames=${JSON.stringify(pagesDataPathnames)}`,
          `appPagesDat

\/_next\/data\/[^/]+\/\[id\]\.json$/.test(item)
    )
    const hasDoubleIndexData = [
      ...pagesDataPathnames,
      ...appPagesDataPathnames,
    ].some((item) => /^\/_next\/data\/[^/]+\/index\/index\.json$/.test(item))


iction policy.
 * When the cache exceeds maxEntries, the least recently used entries are evicted.
 */

const MAX_IMAGE_ENTRIES = parseInt(
  process.env.MAX_IMAGE_CACHE_ENTRIES || '2',
  10
)

class LRUCache {
  constructor(maxEntries) {
    this.maxEntries = maxEntries
    this.cache = new Map()
  }

  get(key) {
    if (!this.cache.has(key)) {
      return undefined
    }
    // Move to end (most recently used)
    const value = this.cache.get(key)
    this.cache.delete(key)
    this.cache.set(key, value)

is.cache.size >= this.maxEntries) {
      const oldestKey = this.cache.keys().next().value
      console.log('cache-handler evicting', oldestKey)
      this.cache.delete(oldestKey)
    }
    this.cache.set(key, value)
  }

  has(key) {
    return this.cach

    return value
  }

  set(key, value) {
    // If key exists, delete it first (will be re-added at end)
    if (this.cache.has(key)) {
      this.cache.delete(key)
    }
    // Evict oldest entries if at capacity
    while (th


fetchViaHTTP } from 'next-test-utils'

describe('Middleware fetches with any HTTP method', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/api/ping.js': `
        export default (req, res) => {
          res.send(JSON.stringify({
            method: req.method,
            headers: {...req.headers},
          }))
        }
      `,
      'middleware.js': `
        import { NextResponse } from 'next/server';

        const HTTP_ECHO_URL = 'https://next-data-api-endpoint.vercel.app/api/ec

l: HTTP_ECHO_URL, method: req.method});
          const json = await response.text()

          const res = NextResponse.next();
          res.headers.set('x-resolved', json ?? '{}');
          return res
        }

        const handlers = {
          'ne

ho-headers';

        export default async (req) => {
          const kind = req.nextUrl.searchParams.get('kind')
          const handler = handlers[kind] ?? handlers['normal-fetch'];

          const response = await handler({ur


ort { nextTestSetup } from 'e2e-utils'

describe('Async modules', () => {
  const { next, isNextDev: dev } = nextTestSetup({
    files: __dirname,
  })

  it('ssr async page modules', async () => {
    const $ = await next.render$('/')
    expect($('#app-value').text()).toBe('hello')
    expect($('#page-value').text()).toBe('42')
  })

  it('csr async page modules', async () => {
    const browser = await next.browser('/')
    expect(await browser.elementByCss('#app-value').text()).toBe('hello')
    expect(

pi/hello')
    expect(res.status).toBe(200)
    const result = await res.json()
    expect(result).toHaveProperty('value', 42)
  })

  it('works with getServerSideProps', async () => {
    const browser = await next.browser('/gssp')
    expect(await browse

await browser.elementByCss('#page-value').text()).toBe('42')
    expect(await browser.elementByCss('#doc-value').text()).toBe('doc value')
  })

  it('works on async api routes', async () => {
    const res = await next.fetch('/a


eslint-disable no-undef */
import {
  ClientValue,
  ClientExpr,
  ClientNumber,
  ClientBoolean,
} from './client-component'

export default function Page() {
  return (

        Server value:{' '}
        {typeof MY_MAGIC_VARIABLE === 'string' ? MY_MAGIC_VARIABLE : 'not set'}

        Client value: <ClientValue />

        Server expr:{' '}
        {typeof process.env.MY_MAGIC_EXPR === 'string'
          ? process.env.MY_MAGIC_EXPR
          :

'}

        Client number: <ClientNumber />

        Server boolean:{' '}
        {typeof MY_BOOLEAN_VARIABLE === 'boolean'
          ? String(MY_BOOLEAN_VARIABLE)
          : 'not set'}

'not set'}

        Client expr: <ClientExpr />

        Server number:{' '}
        {typeof MY_NUMBER_VARIABLE === 'number'
          ? String(MY_NUMBER_VARIABLE)
          : 'not set


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

describe('socket-io', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    dependencies: {
      'socket.io': '4.7.2',
      'socket.io-client': '4.7.2',
      'utf-8-validate': '6.0.3',
      bufferutil: '4.0.8',
    },
    // the socket.io setup relies on patching next's `http.Server` instance,
    // which we can't do when deployed
    skipDeployment: true,
  })

  it('should support socket.io without falling back to polling', asyn

      },
    })

    await Promise.all([
      retry(async () =>
        expect(await browser1.elementByCss('#status').text()).toBe('Connected')
      ),
      retry(async () =>
        expect(await browser2.elementByCss('#status').text()).toBe('Connected

c () => {
    let requestsCount = 0

    const browser1 = await next.browser('/')
    const browser2 = await next.browser('/', {
      beforePageLoad(page) {
        page.on('request', () => {
          requestsCount++
        })


// @ts-check

const defaultCacheHandler =
  require('next/dist/server/lib/cache-handlers/default.external').default

/**
 * @type {import('next/dist/server/lib/cache-handlers/types').CacheHandler}
 */
const cacheHandler = {
  async get(cacheKey, softTags) {
    console.log('WiringModernCacheHandler::get', cacheKey, softTags)
    return defaultCacheHandler.get(cacheKey, softTags)
  },

  async set(cacheKey, pendingEntry) {
    console.log('WiringModernCacheHandler::set', cacheKey)
    return defaultCacheHand

CacheHandler::getExpiration', JSON.stringify(tags))
    return Infinity
  },

  async updateTags(tags) {
    console.log('WiringModernCacheHandler::updateTags', JSON.stringify(tags))
    return defaultCacheHandler.updateTags(tags)
  },
}

module.exports =

ler.set(cacheKey, pendingEntry)
  },

  async refreshTags() {
    console.log('WiringModernCacheHandler::refreshTags')
    return defaultCacheHandler.refreshTags()
  },

  async getExpiration(tags) {
    console.log('WiringModern


etry } from 'next-test-utils'

function makeIndexPage(runtime: string) {
  return `import ReactDOM from 'react-dom'
import Image from 'next/image'

export default function Index() {
  if (typeof window !== 'undefined') {
    window.didHydrate = true
  }
  console.log('__render__')
  return (

{ReactDOM.version}

      <Image
        id="priority-image"
        priority
        src="/noop.png"
        width={300}
        height={400}
      />

  )
}

expo

    it('should only render once in SSR', async () => {
      await next.render('/')
      expect([...next.cliOutput.matchAll(/__render__/g)].length).toBe(1)
    })

    it('no warnings for image related link props', async () => {
      await next.render(

rt const config = {
  runtime: ${JSON.stringify(runtime)}
}
`
}

describe('react-current-version', () => {
  describe('Basics', () => {
    const { next, isTurbopack } = nextTestSetup({
      files: join(__dirname, 'app'),
    })


'/hello/world')
    const $ = cheerio.load(html)
    expect($('#route').text()).toBe('top level route param: [hello|world]')
  })

  it('should render catch-all top-level route with single segment', async () => {
    const html = await next.render('/hello')
    const $ = cheerio.load(html)
    expect($('#route').text()).toBe('top level route param: [hello]')
  })

  it('should render catch-all top-level route with no segments', async () => {
    const html = await next.render('/')
    const $ = cheerio.load

const $ = cheerio.load(html)
    expect($('#route').text()).toBe('nested route param: [hello|world]')
  })

  it('should render catch-all nested route with single segment', async () => {
    const html = await next.render('/nested/hello')
    const $ = che

(html)
    expect($('#route').text()).toBe('top level route param: undefined')
  })

  it('should render catch-all nested route with multiple segments', async () => {
    const html = await next.render('/nested/hello/world')


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

// x-ref: https://github.com/vercel/next.js/issues/45189
describe('edge render - custom _document with edge runtime', () => {
  const { next } = nextTestSetup({
    files: {
      'pages/index.js': new FileRef(
        join(__dirname, 'app', 'pages', 'index.js')
      ),
      'pages/[id].js': new FileRef(join(__dirname, 'app', 'pages', '[id].js')),
      'next.config.js': new FileRef(join(__dirname, 'app', 'next.config.js')),
      'my-ada

 {
          render() {
            return (
              <Html>
                <Head />
                <body>
                  <Main />
                  <NextScript />
                </body>
              </Html>
            )
          }
        }

pter.js': new FileRef(join(__dirname, 'app', 'my-adapter.js')),
      'pages/_document.js': `
        import Document, { Html, Head, Main, NextScript } from 'next/document'
        export default class MyDocument extends Document


eerio from 'cheerio'

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

  it('should rewrite correctly for path at same level as fallback: false SSR', async () => {
    const res = await next.fetch('/hello', { redirect: 'manual' })
    expect(res.status).toBe(200)

    const html = await res.text()
    const

 async () => {
    const res = await next.fetch('/hello/world', { redirect: 'manual' })
    expect(res.status).toBe(200)

    const html = await res.text()
    const $ = cheerio.load(html)

    expect($('#another').text()).toBe('another')
    expect(JSON.p

$ = cheerio.load(html)

    expect($('#another').text()).toBe('another')
    expect(JSON.parse($('#query').text())).toEqual({
      path: ['hello'],
    })
  })

  it('should rewrite correctly for path above fallback: false SSR',


('compiler.define', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  describe('compiler.define', () => {
    let loadedText
    beforeEach(async () => {
      let browser = await next.browser('/')
      loadedText = await browser.elementByCss('body').text()
    })

    it('should render the magic variable on server side', async () => {
      expect(loadedText).toContain('Server value: foobar')
      expect(loadedText).toContain('Client value: foobar')
    })

    it('should render th

de', async () => {
      expect(loadedText).toContain('Server expr: barbaz')
      expect(loadedText).toContain('Client expr: barbaz')
    })

    it('should render the magic expression on client side', async () => {
      expect(loadedText).toContain('Ser

e magic variable on client side', async () => {
      expect(loadedText).toContain('Server value: foobar')
      expect(loadedText).toContain('Client value: foobar')
    })

    it('should render the magic expression on server si


 { nextTestSetup } from 'e2e-utils'

describe('rewrites has condition', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should navigate to a simple rewrite without error', async () => {
    const browser = await next.browser('/')
    await browser.eval('window.beforeNav = 1')

    await browser
      .elementByCss('#to-simple')
      .click()
      .waitForElementByCss('#another')
    expect(await browser.elementByCss('#pathname').text()).toBe('/another')
    expect(JSON.parse(a

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

    await browser
      .elementByCss('#to-has-rewrite')
      .click()
      .waitForElementByCss('#another')
    expect(await browser.elementByCss('#pathname').text()).toBe('/another')
    expect(JSON

wait browser.elementByCss('#query').text())).toEqual({})
    expect(await browser.eval('window.beforeNav')).toBe(1)
  })

  it('should navigate to a has rewrite without error', async () => {
    const browser = await next.browser


t cheerio from 'cheerio'

describe('Fallback Dynamic Route Params', () => {
  const { next } = nextTestSetup({
    files: __dirname,
  })

  it('should have correct fallback query (skeleton)', async () => {
    const html = await next.render('/first')
    const $ = cheerio.load(html)
    const { query } = JSON.parse($('#__NEXT_DATA__').text())
    expect(query).toEqual({})
  })

  it('should have correct fallback query (hydration)', async () => {
    const browser = await next.browser('/second')
    const i

).initialSlug)
    expect(initialSlug).toBeFalsy()

    await browser.waitForElementByCss('#query')

    const hydratedQuery = JSON.parse(
      await browser.elementByCss('#query').text()
    )
    expect(hydratedQuery).toEqual({ slug: 'second' })
  })
})

nitialSlug = await browser.eval(() => (window as any


de, esm = true, pluginOptions = {}) =>
  transform(code, {
    filename: 'noop.js',
    presets: [['@babel/preset-react', { development: false, pragma: '__jsx' }]],
    plugins: [[plugin, pluginOptions]],
    babelrc: false,
    configFile: false,
    sourceType: 'module',
    compact: true,
    caller: {
      name: 'tests',
      supportsStaticESM: esm,
    },
  }).code

describe('babel plugin (next-ssg-transform)', () => {
  describe('getStaticProps support', () => {
    it('should remove separate named

      `)
      expect(output).toMatchInlineSnapshot(
        `"export var __N_SSG=true;export default function Test(){return __jsx("div",null);}"`
      )
    })

    it('should remove combined named export specifiers', () => {
      const output = babel(t

export specifiers', () => {
      const output = babel(trim`
        export { getStaticPaths } from '.'
        export { a as getStaticProps } from '.'

        export default function Test() {
          return <div />
        }


che-handler-image', () => {
  const { next, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
    env: {
      // Set max cache entries to 2 to easily test eviction
      MAX_IMAGE_CACHE_ENTRIES: '2',
    },
  })

  if (skipped) {
    return
  }

  it('should use custom cache handler for image optimization', async () => {
    // First, render the page to get the image URLs
    const $ = await next.render$('/')
    expect($('p').text()).toBe('hello world')

    const smallImgSrc = $

   // Verify cache handler was called for the image
    await retry(() => {
      expect(next.cliOutput).toContain('initialized custom cache-handler')
      expect(next.cliOutput).toContain('cache-handler set')
      expect(next.cliOutput).toMatch(/kind:.*

('#image-small').attr('src')
    expect(smallImgSrc).toContain('/_next/image')

    // Fetch the optimized image to trigger cache handler
    const imageRes = await next.fetch(smallImgSrc)
    expect(imageRes.status).toBe(200)


t-env jest */
import { transformSync } from '@babel/core'

const babel = (code) =>
  transformSync(code, {
    filename: 'page.tsx',
    presets: ['@babel/preset-typescript'],
    plugins: [require('next/dist/build/babel/plugins/next-page-config')],
    babelrc: false,
    configFile: false,
    sourceType: 'module',
    compact: true,
    caller: {
      name: 'tests',
      isDev: false,
    },
  } as any).code

describe('babel plugin (next-page-config)', () => {
  test('export config with type annotation

nfig: PageConfig = {};')

    expect(output).toMatch(`export const config={};`)
  })

  test('export config with AsExpression', () => {
    const output = babel('export const config = {} as PageConfig;')

    expect(output).toMatch('export const config={};


e client'

import { useEffect, useState } from 'react'
import io from 'socket.io-client'

let socket

export default function Home() {
  const [connected, setConnected] = useState(false)
  const [value, setValue] = useState('')

  const socketInitializer = async () => {
    // We call this just to make sure we turn on the websocket server
    await fetch('/api/socket')

    socket = io(undefined, {
      path: '/api/my_awesome_socket',
    })

    socket.on('connect', () => {
      console.log('Connected',

turn
    }
    const value = e.target.value

    setValue(value)
    socket.emit('createdMessage', value)
  }

  useEffect(() => {
    socketInitializer().then(() => {
      setConnected(true)
    })
  }, [])

  return (
    <>
      <span id="status">{con

socket.id)
    })

    socket.on('newIncomingMessage', (msg) => {
      setValue(msg)
    })
  }

  const sendMessageHandler = async (e) => {
    if (!socket) {
      console.error('No socket connection yet for message')
      re


ring-regexp'
import fs from 'fs-extra'

describe('edge-render-getserversideprops', () => {
  const { next } = nextTestSetup({
    files: join(__dirname, 'app'),
  })

  if ((global as any).isNextStart) {
    // Turbopack doesn't have entry chunks for edge routes like Webpack does, so there is no fixed
    // known path where the nft file would be written to.
    ;(process.env.IS_TURBOPACK_TEST ? it.skip : it)(
      'should not output trace files for edge routes',
      async () => {
        /* eslint-disab

)
        ).toBe(true)
        expect(
          await fs.pathExists(
            join(next.testDir, '.next/server/pages/[id].js.nft.json')
          )
        ).toBe(false)
        expect(
          await fs.pathExists(join(next.testDir, '.next/server/pag

le jest/no-standalone-expect */
        expect(await fs.pathExists(join(next.testDir, '.next/pages'))).toBe(
          false
        )
        expect(
          await fs.pathExists(join(next.testDir, '.next/server/pages/[id].js')


m 'eslint'
import { rules } from '@next/eslint-plugin-next'

const NextESLintRule = rules['no-title-in-document-head']

const tests = {
  valid: [
    `import Head from "next/head";

     class Test {
      render() {
        return (
          <Head>
            <title>My page title</title>
          </Head>
        );
      }
     }`,

    `import Document, { Html, Head } from "next/document";

     class MyDocument extends Document {
      render() {
        return (
          <Html>
            <Head>

       return (
            <Head>
              <title>My page title</title>
            </Head>
          );
        }
      }`,
      errors: [
        {
          message:
            'Do not use `<title>` element with `<Head />` component from `next/d

           </Head>
          </Html>
        );
      }
     }

     export default MyDocument;
     `,
  ],

  invalid: [
    {
      code: `
      import { Head } from "next/document";

      class Test {
        render() {


erver/web/spec-extension/response'

it('reflect .set into `set-cookie`', async () => {
  const response = new NextResponse()
  expect(response.cookies.get('foo')?.value).toBe(undefined)
  expect(response.cookies.get('foo')).toEqual(undefined)

  response.cookies
    .set('foo', 'bar', { path: '/test' })
    .set('fooz', 'barz', { path: '/test2' })

  expect(response.cookies.get('foo')?.value).toBe('bar')
  expect(response.cookies.get('fooz')?.value).toBe('barz')

  expect(response.cookies.get('foo')).toEqua

 'foo=bar; Path=/test, fooz=barz; Path=/test2'
  )
  expect(
    Array.from(response.headers.entries()).filter((entry) => {
      return entry[0] === 'set-cookie'
    })
  ).toEqual([
    ['set-cookie', 'foo=bar; Path=/test'],
    ['set-cookie', 'fooz=barz

l({
    name: 'foo',
    path: '/test',
    value: 'bar',
  })
  expect(response.cookies.get('fooz')).toEqual({
    name: 'fooz',
    path: '/test2',
    value: 'barz',
  })

  expect(response.headers.get('set-cookie')).toBe(


eslint-env jest */
import { getBlurImage } from 'next/dist/build/webpack/loaders/next-image-loader/blur'
import { readFile } from 'fs-extra'
import { join } from 'path'

const getImage = (filepath) => readFile(join(__dirname, filepath))

const tracing = () => ({
  traceFn: (fn, ...args) => fn(...args),
  traceAsyncFn: (fn, ...args) => fn(...args),
})

const context = { basePath: '', outputPath: '', isDev: false, tracing }

describe('getBlurImage', () => {
  it('should return image for jpg', async () => {

URL).toBeString()
  })
  it('should return undefined for animated webp', async () => {
    const buffer = await getImage('./images/animated.webp')
    const result = await getBlurImage(
      buffer,
      'webp',
      { width: 400, height: 400 },
      c

  const buffer = await getImage('./images/test.jpg')
    const result = await getBlurImage(
      buffer,
      'jpeg',
      { width: 400, height: 400 },
      context
    )
    expect(result).toBeObject()
    expect(result.data


@edge-runtime/jest-environment
 */

import { expectTypeOf } from 'expect-type'
import { NextRequest } from 'next/dist/server/web/spec-extension/request'

it('should have 1 required parameter for constructor', () => {
  expect(NextRequest.length).toBe(1)
})

it('should allow the 2nd parameter to be undefined', () => {
  const request = new NextRequest('https://vercel.com')
  expectTypeOf(request).toMatchTypeOf<NextRequest>()

  expect(new NextRequest('https://vercel.com')).toHaveProperty(
    'nextUrl.pathna

omEntries(nextRequest.headers)).toEqual(
    Object.fromEntries(request.headers)
  )

  // Second argument should override headers
  const headers = new Headers({ 'x-header': 'some header' })
  const nextRequest2 = new NextRequest(request, { headers })

me',
    '/'
  )
})

it('should clone Request with headers', () => {
  const request = new Request('https://example.com', {
    headers: { 'x-foo': 'bar' },
  })

  const nextRequest = new NextRequest(request)

  expect(Object.fr


lterModuleRules', () => {
  it('should filter module rules correctly', async () => {
    const input = {
      module: { rules: [{ test: 'babel-loader' }, { test: /.*\.css/ }] },
    }
    const expected = [{ test: 'babel-loader' }]

    const output = storybookPlugin.filterModuleRules(input)
    expect(output).toEqual(expected)
  })
})

describe('webpack-config attachReactRefresh', () => {
  it('should skip adding when unrelated', () => {
    const input = { module: { rules: [{ use: 'a' }] } }
    const ex

  rules: [
          {
            use: [
              'next/dist/compiled/@next/react-refresh-utils/dist/loader',
              'rr',
            ],
          },
        ],
      },
    }
    const expected = {
      module: {
        rules: [

pected = { module: { rules: [{ use: 'a' }] } }

    attachReactRefresh(input, 'rr')
    expect(input).toEqual(expected)
  })

  it('should skip adding when existing (shorthand)', () => {
    const input = {
      module: {


ndexOfUint8Array,
  isEquivalentUint8Arrays,
  removeFromUint8Array,
} from 'next/dist/server/stream-utils/uint8array-helpers'

describe('uint8array-helpers', () => {
  it('finds the start index of a nested sequence', () => {
    const haystack = new Uint8Array([1, 2, 3, 4, 5, 6])
    const needle = new Uint8Array([3, 4, 5])
    expect(indexOfUint8Array(haystack, needle)).toBe(2)
  })

  it('handles Buffer input as Uint8Array', () => {
    const haystack = Buffer.from([9, 8, 7, 6, 5, 4])
    const needle =

(indexOfUint8Array(haystack, needle)).toBe(-1)
  })

  it('removes a matching sequence from the middle', () => {
    const haystack = new Uint8Array([10, 20, 30, 40, 50])
    const needle = new Uint8Array([30, 40])

    const result = removeFromUint8Array(

new Uint8Array([7, 6])
    expect(indexOfUint8Array(haystack, needle)).toBe(2)
  })

  it('returns -1 when not found', () => {
    const haystack = new Uint8Array([1, 2, 3, 4])
    const needle = new Uint8Array([4, 5])
    expect


 } from 'next/constants'
import { normalizePagePath } from 'next/dist/shared/lib/page-path/normalize-page-path'
import { requirePage, getPagePath } from 'next/dist/server/require'
import { PageNotFoundError } from 'next/dist/shared/lib/utils'

const sep = '/'
const distDir = join(__dirname, '_resolvedata')
const pathToBundles = join(
  distDir,
  SERVER_DIRECTORY,
  CLIENT_STATIC_FILES_PATH,
  'development',
  'pages'
)

describe('pageNotFoundError', () => {
  it('Should throw error with ENOENT code', () =>

> {
    expect(normalizePagePath('/')).toBe(`${sep}index`)
  })

  it('Should turn _error into /_error', () => {
    expect(normalizePagePath('_error')).toBe(`${sep}_error`)
  })

  it('Should turn /abc into /abc', () => {
    expect(normalizePagePath('/ab

 {
    expect.assertions(1)
    try {
      throw new PageNotFoundError('test')
    } catch (err) {
      expect(err.code).toBe('ENOENT')
    }
  })
})

describe('normalizePagePath', () => {
  it('Should turn / into /index', () =


m 'eslint'
import { rules } from '@next/eslint-plugin-next'

const NextESLintRule = rules['google-font-preconnect']

const tests = {
  valid: [
    `export const Test = () => (
        <div>
          <link rel="preconnect" href="https://fonts.gstatic.com"/>
          <link
            href={process.env.NEXT_PUBLIC_CANONICAL_URL}
            rel="canonical"
          />
          <link
            href={new URL("../public/favicon.ico", import.meta.url).toString()}
            rel="icon"
          />

ssage:
            '`rel="preconnect"` is missing from Google Font. See: https://nextjs.org/docs/messages/google-font-preconnect',
          type: 'JSXOpeningElement',
        },
      ],
    },
    {
      code: `
      export const Test = () => (

 </div>
      )
    `,
  ],

  invalid: [
    {
      code: `
      export const Test = () => (
        <div>
          <link href="https://fonts.gstatic.com"/>
        </div>
      )
    `,
      errors: [
        {
          me


Rule = rules['inline-script-id']

const errorMessage =
  '`next/script` components with inline content must specify an `id` attribute. See: https://nextjs.org/docs/messages/inline-script-id'

const tests = {
  valid: [
    {
      code: `import Script from 'next/script';

      export default function TestPage() {
        return (
          <Script id="test-script">
            {\`console.log('Hello world');\`}
          </Script>
        )
      }`,
    },
    {
      code: `import Script from 'next/script

/>
        )
      }`,
    },
    {
      code: `import Script from 'next/script';

      export default function TestPage() {
        return (
          <Script src="https://example.com" />
        )
      }`,
    },
    {
      code: `import MyScript fro

';

      export default function TestPage() {
        return (
          <Script
            id="test-script"
            dangerouslySetInnerHTML={{
              __html: \`console.log('Hello world');\`
            }}


xtESLintRule = rules['no-assign-module-variable']

const tests = {
  valid: [
    `
      let myModule = {};

      export default function MyComponent() {
        return <></>
      }
    `,
  ],
  invalid: [
    {
      code: `
      let module = {};

      export default function MyComponent() {
        return <></>
      }
      `,
      errors: [
        {
          message:
            'Do not assign to the variable `module`. See: https://nextjs.org/docs/messages/no-assign-module-variable',
        },

variable', () => {
  new RuleTester({
    languageOptions: {
      ecmaVersion: 2018,
      sourceType: 'module',
      parserOptions: {
        ecmaFeatures: {
          modules: true,
          jsx: true,
        },
      },
    },
  }).run('eslint', Nex

      ],
    },
  ],
}

describe('no-assign-module-


} from '@next/eslint-plugin-next'

const NextESLintRule = rules['no-async-client-component']

const message =
  'Prevent Client Components from being async functions. See: https://nextjs.org/docs/messages/no-async-client-component'

const tests = {
  valid: [
    `
    // single line
    export default async function MyComponent() {
      return <></>
    }
    `,
    `
    // single line capitalization
    "use client"

    export default async function myFunction() {
      return ''
    }
    `,
    `

  }

    export default myFunction
    `,
    `
    // arrow function
    "use client"

    const myFunction = () => {
      return ''
    }

    export default myFunction
    `,
  ],
  invalid: [
    {
      code: `
      // single line
      "use client"

 // multiple line
    async function MyComponent() {
      return <></>
    }

    export default MyComponent
    `,
    `
    // multiple line capitalization
    "use client"

    async function myFunction() {
      return ''


} from '@next/eslint-plugin-next'

const NextESLintRule = rules['no-document-import-in-page']

const tests = {
  valid: [
    {
      code: `import Document from "next/document"

    export default class MyDocument extends Document {
      render() {
        return (
          <Html>
          </Html>
        );
      }
    }
    `,
      filename: 'pages/_document.js',
    },
    {
      code: `import Document from "next/document"

    export default class MyDocument extends Document {
      render() {

ds NDocument {
      render() {
        return (
          <Html>
          </Html>
        );
      }
    }
    `,
      filename: 'pages/_document/index.js',
    },
    {
      code: `import NDocument from "next/document"

    export default class Docume

     return (
          <Html>
          </Html>
        );
      }
    }
    `,
      filename: 'pages/_document.page.tsx',
    },
    {
      code: `import NDocument from "next/document"

    export default class Document exten


} from '@next/eslint-plugin-next'

const NextESLintRule = rules['no-head-element']

const message =
  'Do not use `<head>` element. Use `<Head />` from `next/head` instead. See: https://nextjs.org/docs/messages/no-head-element'

const tests = {
  valid: [
    {
      code: `import Head from 'next/head';

      export class MyComponent {
        render() {
          return (
            <div>
              <Head>
                <title>My page title</title>
              </Head>
            </div>

                <title>My page title</title>
              </Head>
            </div>
          );
        }
      }
    `,
      filename: 'pages/index.tsx',
    },
    {
      code: `
      export default function Layout({ children }) {
        return (

);
        }
      }
    `,
      filename: 'pages/index.js',
    },
    {
      code: `import Head from 'next/head';

      export class MyComponent {
        render() {
          return (
            <div>
              <Head>


ut-pages-dir')
const withAppDir = path.join(__dirname, 'with-app-dir')

const linters = {
  withoutPages: new Linter({
    cwd: withoutPagesDir,
    configType: 'eslintrc',
  }),
  withApp: new Linter({
    cwd: withAppDir,
    configType: 'eslintrc',
  }),
  withNestedPages: new Linter({
    cwd: withNestedPagesDir,
    configType: 'eslintrc',
  }),
  withCustomPages: new Linter({
    cwd: withCustomPagesDir,
    configType: 'eslintrc',
  }),
}

const linterConfig: any = {
  rules: {
    'no-html-link-for-

es: {
    'no-html-link-for-pages': [
      2,
      path.join(withCustomPagesDir, 'custom-pages'),
    ],
  },
}
const linterConfigWithMultipleDirectories = {
  ...linterConfig,
  rules: {
    'no-html-link-for-pages': [
      2,
      [
        path.join

pages': [2],
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      modules: true,
      jsx: true,
    },
  },
}
const linterConfigWithCustomDirectory: any = {
  ...linterConfig,
  rul


Rule = rules['no-location-assign-relative-destination']

const err = (expression: string) => ({
  messageId: 'noLocationAssign',
  data: { expression },
})

describe('no-location-assign-relative-destination', () => {
  new RuleTester({
    languageOptions: {
      ecmaVersion: 2018,
      sourceType: 'module',
      parserOptions: {
        ecmaFeatures: {
          modules: true,
          jsx: true,
        },
      },
    },
  }).run('eslint', NextESLintRule, {
    valid: [
      // Reading href is fine

 (with protocol) are allowed
      `location.href = 'https://example.com'`,
      `window.location.href = 'https://example.com/path'`,
      `globalThis.location.href = 'http://example.com'`,
      `location.assign('https://example.com')`,
      `window.lo

      `const href = location.href`,
      `const url = window.location.href`,
      // location.replace is not covered by this rule
      `location.replace('/foo')`,
      `window.location.replace('/foo')`,
      // Absolute URLs


 { RuleTester } from 'eslint'
import { rules } from '@next/eslint-plugin-next'

const NextESLintRule = rules['no-script-component-in-head']

const message =
  '`next/script` should not be used in `next/head` component. Move `<Script />` outside of `<Head>` instead. See: https://nextjs.org/docs/messages/no-script-component-in-head'

const tests = {
  valid: [
    `import Script from "next/script";
     const Head = ({children}) => children

    export default function Index() {
      return (
        <Head>

 return (
            <Head>
              <Script></Script>
            </Head>
        );
      }`,
      filename: 'pages/index.js',
      errors: [{ message }],
    },
  ],
}

describe('no-script-component-in-head', () => {
  new RuleTester({
    langu

          <Script></Script>
        </Head>
      );
    }
    `,
  ],

  invalid: [
    {
      code: `
      import Head from "next/head";
      import Script from "next/script";

      export default function Index() {


Rule = rules['no-styled-jsx-in-document']

const tests = {
  valid: [
    {
      filename: 'pages/_document.js',
      code: `import Document, { Html, Head, Main, NextScript } from 'next/document'

        export class MyDocument extends Document {
          static async getInitialProps(ctx) {
            const initialProps = await Document.getInitialProps(ctx)
            return { ...initialProps }
          }

          render() {
            return (
              <Html>
                <Head />

         <body>
                  <Main />
                  <NextScript />
                </body>
              </Html>
            )
          }
        }`,
    },
    {
      filename: 'pages/_document.js',
      code: `impor


Rule = rules['no-unwanted-polyfillio']

const tests = {
  valid: [
    `import {Head} from 'next/document';

      export class Blah extends Head {
        render() {
          return (

Hello title

          );
        }
    }`,
    `import {Head} from 'next/document';

      export class Blah extends Head {
        render() {
          return (

om 'next/script';

      export function MyApp({ Component, pageProps }) {
          return (
            <div>
              <Component {...pageProps} />
              <Script src='https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver' />

Hello title

          );
        }
    }`,
    `import Script fr


 the edge-runtime env setup
// so that we test node runtime properly
import { expectTypeOf } from 'expect-type'
import { NextRequest } from 'next/dist/server/web/spec-extension/request'

it('should have 1 required parameter for constructor', () => {
  expect(NextRequest.length).toBe(1)
})

it('should allow the 2nd parameter to be undefined', () => {
  const request = new NextRequest('https://vercel.com')
  expectTypeOf(request).toMatchTypeOf<NextRequest>()

  expect(new NextRequest('https://vercel.com')).to

uest(request)

  expect(Object.fromEntries(nextRequest.headers)).toEqual(
    Object.fromEntries(request.headers)
  )

  // Second argument should override headers
  const headers = new Headers({ 'x-header': 'some header' })
  const nextRequest2 = new Next

HaveProperty(
    'nextUrl.pathname',
    '/'
  )
})

it('should clone Request with headers', () => {
  const request = new Request('https://example.com', {
    headers: { 'x-foo': 'bar' },
  })

  const nextRequest = new NextReq


erver/config'
import stripAnsi from 'strip-ansi'

describe('warnOptionHasBeenMovedOutOfExperimental', () => {
  let spy: jest.SpyInstance
  beforeAll(() => {
    spy = jest.spyOn(console, 'warn').mockImplementation((...args) => {
      const [prefix, ...restArgs] = args
      const formattedFirstArg = stripAnsi(prefix)
      // pass the rest of the arguments to the spied console.warn
      // @ts-expect-error accessing the mocked console.warn
      console.warn.mock.calls.push([formattedFirstArg, ...restArg

config.js',
      false
    )

    warnOptionHasBeenMovedOutOfExperimental(
      {
        experimental: {},
      },
      'skipTrailingSlashRedirect',
      'skipTrailingSlashRedirect',
      'next.config.js',
      false
    )

    expect(spy).not.toHa

s])
    })
  })

  it('should not log warning message without experimental config', () => {
    warnOptionHasBeenMovedOutOfExperimental(
      {},
      'skipTrailingSlashRedirect',
      'skipTrailingSlashRedirect',
      'next.


Rule = rules['google-font-display']

const tests = {
  valid: [
    `import Head from "next/head";

     export default Test = () => {
      return (
        <Head>
          <link href={test} rel="test" />
          <link
            href={process.env.NEXT_PUBLIC_CANONICAL_URL}
            rel="canonical"
          />
          <link
            href={new URL("../public/favicon.ico", import.meta.url).toString()}
            rel="icon"
          />
          <link
            href="https://fonts.googleapis.

     render() {
        return (
          <Html>
            <Head>
              <link
                href="https://fonts.googleapis.com/css?family=Krona+One&display=swap"
                rel="stylesheet"
              />
            </Head>
          <

com/css2?family=Krona+One&display=optional"
            rel="stylesheet"
          />
        </Head>
      );
     };
    `,

    `import Document, { Html, Head } from "next/document";

     class MyDocument extends Document {


const ERROR_MSG_GOOGLE_ANALYTICS = `Prefer \`GoogleAnalytics\` component from \`@next/third-parties/google\` when using the inline script for Google Analytics. See: ${url}`
const ERROR_MSG_GOOGLE_TAG_MANAGER = `Prefer \`GoogleTagManager\` component from \`@next/third-parties/google\` when using the inline script for Google Tag Manager. See: ${url}`

const tests = {
  valid: [
    `import Script from 'next/script'

      export class Blah extends Head {
        render() {
          return (
            <div>

-analytics">
                {\`
                  window.dataLayer = window.dataLayer || [];
                  function gtag(){window.dataLayer.push(arguments);}
                  gtag('js', new Date());

                  gtag('config', 'GA_MEASUREMENT_I


oreInteractive` strategy should not be used outside of `pages/_document.js`. See: https://nextjs.org/docs/messages/no-before-interactive-script-outside-document"

const tests = {
  valid: [
    {
      code: `
      import Document, { Html, Main, NextScript } from 'next/document'
      import Script from 'next/script'

      class MyDocument extends Document {
        render() {
          return (
            <Html>
              <Head>
                <meta charSet="utf-8" />
              </Head>

n.js?a=scriptBeforeInteractive"
                  strategy="beforeInteractive"
                ></Script>
              </body>
            </Html>
          )
        }
      }

      export default MyDocument
      `,
      filename: 'pages/_document.js'

      <body>
                <Main />
                <NextScript />
                <Script
                  id="scriptBeforeInteractive"
                  src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.mi


Rule = rules['no-head-import-in-document']

const tests = {
  valid: [
    {
      code: `import Document, { Html, Head, Main, NextScript } from 'next/document'

      class MyDocument extends Document {
        static async getInitialProps(ctx) {
          //...
        }

        render() {
          return (
            <Html>
              <Head>
              </Head>
            </Html>
          )
        }
      }

      export default MyDocument
    `,
      filename: 'pages/_document.tsx',
    },

 width=device-width" />
          </Head>
        );
      }
    `,
      filename: 'pages/index.tsx',
    },
  ],
  invalid: [
    {
      code: `
      import Document, { Html, Main, NextScript } from 'next/document'
      import Head from 'next/head'

   {
      code: `import Head from "next/head";

      export default function IndexPage() {
        return (
          <Head>
            <title>My page title</title>
            <meta name="viewport" content="initial-scale=1.0,


Rule = rules['no-img-element']

const message =
  'Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element'

const tests = {
  valid: [
    `import { Image } from 'next/image';

      export class MyComponent {
        render() {
          return (
            <div>
              <Image

    render() {
          return (
            <picture>
              <img
                src="/test.png"
                alt="Test picture"
                width={500}
                height={500}
              />
            </picture>
          );

                src="/test.png"
                alt="Test picture"
                width={500}
                height={500}
              />
            </div>
          );
        }
      }`,
    `export class MyComponent {


m 'eslint'
import { rules } from '@next/eslint-plugin-next'

const NextESLintRule = rules['no-sync-scripts']

const message =
  'Synchronous scripts should not be used. See: https://nextjs.org/docs/messages/no-sync-scripts'

const tests = {
  valid: [
    `import {Head} from 'next/document';

      export class Blah extends Head {
        render() {
          return (

Hello title

ps} ></script>
            </div>
          );
        }
    }`,
  ],

  invalid: [
    {
      code: `
      import {Head} from 'next/document';

        export class Blah extends Head {
          render() {
            return (
              <div>

);
        }
    }`,
    `import {Head} from 'next/document';

      export class Blah extends Head {
        render(props) {
          return (

Hello title


Rule = rules['no-page-custom-font']

const filename = 'pages/_document.js'

const tests = {
  valid: [
    {
      code: `import Document, { Html, Head } from "next/document";
    class MyDocument extends Document {
      render() {
        return (
          <Html>
            <Head>
              <link
                href="https://fonts.googleapis.com/css2?family=Krona+One&display=swap"
                rel="stylesheet"
              />
            </Head>
          </Html>
        );
      }
    }
    ex

   <Head>
              <link
                href="https://fonts.googleapis.com/css2?family=Krona+One&display=swap"
                rel="stylesheet"
              />
            </Head>
          </Html>
        );
      }
    }
    export default Documen

port default MyDocument;`,
      filename,
    },
    {
      code: `import NextDocument, { Html, Head } from "next/document";
    class Document extends NextDocument {
      render() {
        return (
          <Html>


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

describe('terser-class-static-blocks', () => {
  const { next, isNextDeploy } = nextTestSetup({
    files: __dirname,
    nextConfig: {},
  })

  it('should work using cheerio', async () => {
    const $ = await next.render$('/')
    expect($('p').text()).toBe('hello world')
  })

  if (!isNextDeploy) {
    it('should have stripped away all comments', async () => {
      const chunksDir = path.join(next.testDir, '.nex

 await next.readFile(path.join('.next/static', chunk))
          ).not.toContain('/*')

          expect(
            await next.readFile(path.join('.next/static', chunk))
          ).not.toContain('My JSDoc comment that')
        })
      )
    })
  }
})

t/static')
      const chunks = glob.sync('**/*.js', {
        cwd: chunksDir,
      })

      expect(chunks.length).toBeGreaterThan(0)

      await Promise.all(
        chunks.map(async (chunk) => {
          expect(


('unstable-cache-foreground-revalidate', () => {
  const { next, isNextDev } = nextTestSetup({
    files: __dirname,
  })

  if (isNextDev) {
    it.skip('should not run in dev mode', () => {})
    return
  }

  it('should block and wait for fresh data when ISR page revalidate time is greater than unstable_cache TTL', async () => {
    // Initial render to warm up cache
    await next.render('/isr-10')

    // Record initial log position
    const initialLogLength = next.cliOutput.length

    // Wait for bo

evalidation to complete
    await new Promise((resolve) => setTimeout(resolve, 2000))

    // Get logs since the initial render
    const logs = next.cliOutput.substring(initialLogLength)

    const cacheExecutions = [
      ...logs.matchAll(/\[TEST\] unst

th ISR and unstable_cache to become stale
    await new Promise((resolve) => setTimeout(resolve, 11000))

    // This request triggers ISR background revalidation
    await next.render('/isr-10')

    // Wait for ISR background r


import { unstable_cache } from 'next/cache'

export const revalidate = 10

const getCachedData = unstable_cache(
  async () => {
    const generatedAt = Date.now()

    // Log when this function is actually executed
    console.log('[TEST] unstable_cache callback executed at:', generatedAt)

    // Add a delay to simulate expensive operation
    await new Promise((resolve) => setTimeout(resolve, 100))

    return {
      generatedAt,
      random: Math.random(),
    }
  },
  ['cached-data'],
  {
    revalid

age render completed with cache data from:',
    cachedData.generatedAt
  )

  return (

{pageRenderStart}

{cachedData.generatedAt}

{cachedData.random}

ate: 5,
  }
)

export default async function Page() {
  const pageRenderStart = Date.now()
  console.log('[TEST] Page render started at:', pageRenderStart)

  const cachedData = await getCachedData()

  console.log(
    '[TEST] P


findPort, initNextServerScript, killApp, retry } from 'next-test-utils'
import path from 'node:path'
import fs from 'fs-extra'
import os from 'os'

describe('app-dir action body finalize with nodejs middleware and output-standalone', () => {
  const { next } = nextTestSetup({
    files: __dirname,
    skipStart: true,
  })

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

  beforeAll(async () => {
    tmpFolder = path.join(os.tmpdir(), 'next-standalone-' + Date.now())
    await fs.mkdirp(tmp

ync finalize () { \nawait new Promise((resolve) => setTimeout(resolve, (Math.random() * 1000) + 1000));\n'
        )
      }
    )

    const distFolder = path.join(tmpFolder, 'test')
    await fs.move(path.join(next.testDir, '.next/standalone'), distFolde

Folder)

    await next.build()
    await next.patchFile(
      '.next/standalone/node_modules/next/dist/server/body-streams.js',
      (content) => {
        return content.replace(
          'async finalize () {',
          'as


from 'e2e-utils'
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'next-types-plugin',
  () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
    })

    if (skipped) return

    it('should have type for root page', async () => {
      expect(await next.hasFile('app/page.tsx')).toBe(true)
      expect(await next.hasFile('.next/types/app/page.ts')).toBe(true)
    })
    it('should have type for root layout', async () => {
      expect(await next.hasFile('app/layout.tsx'

t(await next.hasFile('.next/types/app/nested/page.ts')).toBe(true)
    })
    it('should have type for nested layout', async () => {
      expect(await next.hasFile('app/nested/layout.tsx')).toBe(true)
      expect(await next.hasFile('.next/types/app/neste

)).toBe(true)
      expect(await next.hasFile('.next/types/app/layout.ts')).toBe(true)
    })
    it('should have type for nested page', async () => {
      expect(await next.hasFile('app/nested/page.tsx')).toBe(true)
      expec


 { nextTestSetup } from 'e2e-utils'

const strictRouteTypes =
  process.env.__NEXT_EXPERIMENTAL_STRICT_ROUTE_TYPES === 'true'

// This next-types-plugin feature only works in webpack
;(process.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'app-dir - sync-params-type-check',
  () => {
    const { next } = nextTestSetup({
      files: __dirname,
      skipStart: true,
    })

    it('should pass build with Promise params', async () => {
      const { exitCode } = await next.build()
      expect(exitCod

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

      }
      `
      )
      const { exitCode, cliOutput } = await next.build()
      expect(exitCode).toBe(1)
      expect(cliOutput).toMatch(
        strictRouteTypes
          ? /

e).toBe(0)
    })

    it('should fail build with sync params', async () => {
      await next.patchFile(
        'app/blog/[slug]/page.tsx',
        `
      interface Params { slug: string }
      export default function Page({


.env.IS_TURBOPACK_TEST ? describe.skip : describe)(
  'next-types-plugin private-folder-convention',
  () => {
    const { next, skipped } = nextTestSetup({
      files: __dirname,
    })

    if (skipped) return

    it('should have type for root page', async () => {
      expect(await next.hasFile('app/page.tsx')).toBe(true)
      expect(await next.hasFile('.next/types/app/page.ts')).toBe(true)
    })
    it('should have type for root layout', async () => {
      expect(await next.hasFile('app/layout.tsx'


@edge-runtime/jest-environment
 */

import { NextResponse } from 'next/dist/server/web/spec-extension/response'

const toJSON = async (response: Response) => ({
  body: await response.json(),
  contentType: response.headers.get('content-type'),
  status: response.status,
})

it('automatically parses and formats JSON', async () => {
  expect(await toJSON(NextResponse.json({ message: 'hello!' }))).toMatchObject({
    contentType: 'application/json',
    body: { message: 'hello!' },
  })

  expect(
    await t

({ error: { code: 'bad_request' } }, { status: 400 })
    )
  ).toMatchObject({
    contentType: 'application/json',
    body: { error: { code: 'bad_request' } },
    status: 400,
  })

  expect(await toJSON(NextResponse.json(null))).toMatchObject({
    co

oJSON(NextResponse.json({ status: 'success' }, { status: 201 }))
  ).toMatchObject({
    contentType: 'application/json',
    body: { status: 'success' },
    status: 201,
  })

  expect(
    await toJSON(
      NextResponse.json


t css from '../noop-template'

describe('basic test', () => {
  test('should minify css', async () => {
    const input = css`
      p {
        color: yellow;
      }
    `

    const res = await postcss([mod()]).process(input, {
      from: 'input.css',
      to: 'output.css',
    })

    expect(res.css).toBe('p{color:#ff0}')
  })

  test('should be able to declare layer names', async () => {
    // @layer b is equivlaent to @layer b {}
    const input = css`
      @layer b {
        ._5-enzrfpb:lang(ar)

    }

      @layer b;
    `

    const res = await postcss([mod()]).process(input, {
      from: 'input.css',
      to: 'output.css',
    })

    expect(res.css).toBe(
      '@layer b{._5-enzrfpb:lang(ar){font-family:myriad-arabic}}@layer b;'
    )
  })
}

{
          font-family: myriad-arabic;
        }


css'

import mod from 'next/dist/compiled/cssnano-simple/index'
import css from '../noop-template'

describe('exclude all test', () => {
  test('should not transform css', async () => {
    const input = css`
      p {
        /* test */
        color: yellow;
      }
    `

    const res = await postcss([mod({ excludeAll: true })]).process(input, {
      from: 'input.css',
      to: 'output.css',
    })

    expect(res.css).toBe(input)
  })

  test('should strip comments and spaces from css', async () => {

        normalizeWhitespace: { exclude: false },
      }),
    ]).process(input, {
      from: 'input.css',
      to: 'output.css',
    })

    expect(res.css).toMatchInlineSnapshot(`"p{color:yellow}.empty{}"`)
  })

  test('should enable rule with empty

    const input = css`
      p {
        /* test */
        color: yellow;
      }
      .empty {
      }
    `

    const res = await postcss([
      mod({
        excludeAll: true,
        discardComments: { removeAll: true },


ration', () => {
    const eslintConfigAfterSetupJSON = execSync(
      // Pass explicit absolute path to not get affected by the root eslint config.
      `pnpm eslint --config ${join(__dirname, 'eslint.config.mjs')} --print-config ${join(__dirname, 'test.js')}`,
      {
        cwd: __dirname,
        encoding: 'utf8',
        stdio: ['pipe', 'pipe', 'inherit'],
      }
    )

    const { settings, languageOptions, ...eslintConfigAfterSetup } = JSON.parse(
      eslintConfigAfterSetupJSON
    )

    expec

ers': expect.any(Object),
        'import/resolver': expect.any(Object),
        react: {
          version: 'detect',
        },
      },
    })

    expect(getEslintConfigSnapshot(eslintConfigAfterSetup))
      .toMatchInlineSnapshot(`
     {
       "lan

t({
      parser: languageOptions.parser,
      settings,
    }).toEqual({
      // parser: require.resolve('eslint-config-next')
      parser: expect.stringContaining('eslint-config-next'),
      settings: {
        'import/pars


resolved configuration', () => {
    const eslintConfigAfterSetupJSON = execSync(
      // Pass explicit absolute path to not get affected by the root eslint config.
      `pnpm eslint --config ${join(__dirname, 'eslint.config.mjs')} --print-config ${join(__dirname, 'test.js')}`,
      {
        cwd: __dirname,
        encoding: 'utf8',
        stdio: ['pipe', 'pipe', 'inherit'],
      }
    )

    const { settings, languageOptions, ...eslintConfigAfterSetup } = JSON.parse(
      eslintConfigAfterSetupJSON

rt/resolver': expect.any(Object),
        react: {
          version: 'detect',
        },
      },
    })

    expect(getEslintConfigSnapshot(eslintConfigAfterSetup))
      .toMatchInlineSnapshot(`
     {
       "language": "@/js",
       "linterOptions":

    )

    expect({
      parser: languageOptions.parser,
      settings,
    }).toEqual({
      parser: expect.stringContaining('eslint-config-next'),
      settings: {
        'import/parsers': expect.any(Object),
        'impo


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

const getImage = (filepath) => readFile(join(__dirname, filepath))

describe.each([false, true])(
  'detectContentType with imgOptSkipMetadata: %s',
  (imgOptSkipMetadata) => {
    it('should return null for empty buffer', async () => {
      expect(await detectContentType(Buffer.alloc(0), imgOptSkipMetadata)).toBe(
        null
      )
    })
    it('should return null for unrecognized buffer', async () => {
      expect(
        await detectContentType

ctContentType(buffer, imgOptSkipMetadata)).toBe(
        'image/jpeg'
      )
    })
    it('should return png', async () => {
      const buffer = await getImage('./images/test.png')
      expect(await detectContentType(buffer, imgOptSkipMetadata)).toBe(

(
          Buffer.from([0xa, 0xb, 0xc]),
          imgOptSkipMetadata
        )
      ).toBe(null)
    })
    it('should return jpg', async () => {
      const buffer = await getImage('./images/test.jpg')
      expect(await dete


mizer'
import type { IncomingMessage, ServerResponse } from 'http'

describe('fetchInternalImage', () => {
  describe('response size limit', () => {
    it('should throw error when response has no buffers', async () => {
      const mockReq = {} as IncomingMessage
      const mockRes = {} as ServerResponse
      const maximumResponseBody = 300_000_000

      const handleRequest = jest.fn(async (_req: IncomingMessage, res: any) => {
        res.statusCode = 200
        res.getHeader = jest.fn(() => 'image/jp

error).toBeInstanceOf(ImageError)
      expect((error as ImageError).statusCode).toBe(400)
      expect((error as ImageError).message).toBe(
        '"url" parameter is valid but internal response is invalid'
      )
    })

    it('should throw error when

eg')
        res.end()
      })

      const error = await fetchInternalImage(
        '/test-image.jpg',
        mockReq,
        mockRes,
        maximumResponseBody,
        handleRequest
      ).catch((e) => e)

      expect(


ort { getMaxAge } from 'next/dist/server/image-optimizer'

describe('getMaxAge', () => {
  it('should return 0 when no cache-control provided', () => {
    expect(getMaxAge(undefined)).toBe(0)
  })
  it('should return 0 when cache-control is null', () => {
    expect(getMaxAge(null)).toBe(0)
  })
  it('should return 0 when cache-control is empty string', () => {
    expect(getMaxAge('')).toBe(0)
  })
  it('should return 0 when cache-control max-age is not a number', () => {
    expect(getMaxAge('max-age=foo

Be(9999)
  })
  it('should return cache-control MAX-AGE uppercase', () => {
    expect(getMaxAge('MAX-AGE=9999')).toBe(9999)
  })
  it('should return cache-control s-maxage lowercase', () => {
    expect(getMaxAge('s-maxage=9999')).toBe(9999)
  })
  it('sh

')).toBe(0)
  })
  it('should return 0 when cache-control is no-cache', () => {
    expect(getMaxAge('no-cache')).toBe(0)
  })
  it('should return cache-control max-age lowercase', () => {
    expect(getMaxAge('max-age=9999')).to


 'next/dist/server/lib/disk-lru-cache.external'

async function writeEntry(
  cacheDir: string,
  key: string,
  sizeInBytes: number,
  expireAt: number = Date.now() + 60_000
) {
  const dir = join(cacheDir, key)
  const buffer = Buffer.alloc(sizeInBytes, 0x42) // Fill with dummy data
  await promises.mkdir(dir, { recursive: true })
  await promises.writeFile(join(dir, `${expireAt}.bin`), buffer)
}

async function readEntry(cacheDir: string, key: string) {
  const dir = join(cacheDir, key)
  const [file] =

cheDir: string
): Promise<Array<{ key: string; size: number; expireAt: number }>> {
  const keys = await promises.readdir(cacheDir).catch(() => [])
  const entries: Array<{ key: string; size: number; expireAt: number }> = []

  for (const key of keys) {

await promises.readdir(dir)
  const buffer = await promises.readFile(join(dir, file))
  const [expireAtStr] = file.split('.')
  return { size: buffer.byteLength, expireAt: Number(expireAtStr) }
}

async function initEntries(
  ca


 matchLocalPattern,
  hasLocalMatch as hasMatch,
} from 'next/dist/shared/lib/match-local-pattern'

const m = (p: LocalPattern, urlPathAndQuery: string) =>
  matchLocalPattern(p, new URL(urlPathAndQuery, 'http://n'))

describe('matchLocalPattern', () => {
  it('should match anything when no pattern is defined', () => {
    const p = {} as const
    expect(m(p, '/')).toBe(true)
    expect(m(p, '/path')).toBe(true)
    expect(m(p, '/path/to')).toBe(true)
    expect(m(p, '/path/to/file')).toBe(true)
    expect

= {
      search: '',
    } as const
    expect(m(p, '/')).toBe(true)
    expect(m(p, '/path')).toBe(true)
    expect(m(p, '/path/to')).toBe(true)
    expect(m(p, '/path/to/file')).toBe(true)
    expect(m(p, '/path/to/file.txt')).toBe(true)
    expect(m(p,

(m(p, '/path/to/file.txt')).toBe(true)
    expect(m(p, '/path/to/file?q=1')).toBe(true)
    expect(m(p, '/path/to/file?q=1&a=two')).toBe(true)
  })

  it('should match any path without a search query string', () => {
    const p