Repository: vercel/next.js
File: test/lib/e2e-utils/index.ts (TypeScript)

Code before:
  }
}

jest.setTimeout(testTimeout)

const testsFolder = path.join(__dirname, '..', '..')

let testFile
const testFileRegex = /\.test\.(js|tsx?)/

const visitedModules = new Set()
const checkParent = (mod) => {
  if (!mod?.parent || visitedModules.has(mod)) return
  testFile = mod.parent.filename || ''
  visitedModules.add(mod)

  if (!testFileRegex.test(testFile)) {
    checkParent(mod.parent)
  }
}
checkParent(module)

process.env.TEST_FILE_PATH = testFile

let testMode = process.env.NEXT_TEST_MODE

if (!testFileRegex.test(testFile)) {
  throw new Error(
    `e2e-utils imported from non-test file ${testFile} (must end with .test.(js,ts,tsx)`
  )
}

const testFolderModes = ['e2e', 'development', 'production']

const testModeFromFile = testFolderModes.find((mode) =>
  testFile.startsWith(path.join(testsFolder, mode))
)

if (testModeFromFile === 'e2e') {
  const validE2EModes = ['dev', 'start', 'deploy']

  if (!process.env.NEXT_TEST_JOB && !testMode) {
    require('console').warn(
      'Warn: no NEXT_TEST_MODE set, using default of start'
    )
    testMode = 'start'
  }
  assert(
    validE2EModes.includes(testMode!),
    `NEXT_TEST_MODE must be one of ${validE2EModes.join(
      ', '

Review comment (suggestion):
I worry that parsing positional args and patching `global.it`/`global.test` couples us too tightly to Jest internals and call signatures.

Couldn't we do something like this?

```ts
const setupTimeout = /* 120/240 or env override */
const perTestTimeout = process.env.NEXT_E2E_TEST_TIMEOUT
  ? Number.parseInt(process.env.NEXT_E2E_TEST_TIMEOUT, 10)
  : 60_000

if (testMode !== 'dev') {
  jest.setTimeout(perTestTimeout)
  jest.retryTimes(1)
} else {
  jest.setTimeout(setupTimeout)
}
```

Then pass `setupTimeout` explicitly to setup/teardown hooks, e.g.:

```ts
beforeAll(async () => { next = await createNext(options) }, setupTimeout)
afterAll(async () => { await next?.destroy() }, setupTimeout)
afterAll(async () => { }, setupTimeout)
```

One caveat is that we also have suites that call `createNext` directly but maybe that's ok

Code after:
}

jest.setTimeout(setupTimeout)

type E2ETestGlobal = typeof globalThis & {
  __NEXT_E2E_TEST_CONFIG_PATCHED__?: boolean
  __NEXT_E2E_WRAPPED_TEST_FNS__?: WeakMap<Function, Function>
}

const wrapJestTestFn = <T extends Function>(fn: T): T => {
  const e2eGlobal = global as E2ETestGlobal
  const wrappedFns =
    e2eGlobal.__NEXT_E2E_WRAPPED_TEST_FNS__ ??
    (e2eGlobal.__NEXT_E2E_WRAPPED_TEST_FNS__ = new WeakMap())
  const existing = wrappedFns.get(fn)
  if (existing) return existing as T

  const wrapped = new Proxy(fn, {
    apply(target, thisArg, argArray: unknown[]) {
      const args = [...argArray]
      if (
        args.length >= 2 &&
        typeof args[1] === 'function' &&
        args[2] === undefined
      ) {
        args[2] = individualTestTimeout
      }

      const result = Reflect.apply(target, thisArg, args)
      return typeof result === 'function' ? wrapJestTestFn(result) : result
    },
    get(target, prop, receiver) {
      const value = Reflect.get(target, prop, receiver)
      return typeof value === 'function' ? wrapJestTestFn(value) : value
    },
  })

  wrappedFns.set(fn, wrapped)
  return wrapped as T
}

const testsFolder = path.join(__dirname, '..', '..')

let testFile
const testFileRegex = /\.test\.(js|tsx?)/

const visitedModules = new Set()
const checkParent = (mod) => {
  if (!mod?.parent || visitedModules.has(mod)) return
  testFile = mod.parent.filename || ''
  visitedModules.add(mod)