From 7da98e13183864ebc23ffe7aaec07c566c83a6a5 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Mon, 18 May 2026 09:51:36 +0200 Subject: [PATCH 1/4] Convert more tests from createNext -> nextTestSetup (#93799) ## What? Converts more tests that use `createNext` to `nextTestSetup` Follow-up to #93767 --------- Co-authored-by: Cursor --- contributing/core/testing.md | 6 +- .../create-next-app-default.test.ts | 84 ++++++++-- .../asset-prefix.test.ts | 27 +-- .../app-hmr/server-restart.test.ts | 17 +- .../basic/hmr/run-basic-hmr-test.util.ts | 12 +- test/development/basic/next-rs-api.test.ts | 129 +++++++-------- .../basic/project-directory-rename.test.ts | 24 ++- .../start-no-build/start-no-build.test.ts | 20 +-- .../create-root-layout.test.ts | 27 ++- .../avoid-popstate-flash.test.ts | 17 +- .../search-params/search-params.test.ts | 12 +- .../stale-prefetch-entry.test.ts | 17 +- .../ppr-unstable-cache.test.ts | 19 +-- .../segment-cache-revalidation.test.ts | 15 +- test/e2e/next-font/with-proxy.test.ts | 29 ++-- test/e2e/next-script/index.test.ts | 76 ++++----- .../rewrite-request-smuggling.test.ts | 16 +- test/e2e/streaming-ssr/index.test.ts | 17 +- .../turbopack-worker-asset-prefix.test.ts | 110 ++++++------ test/lib/e2e-utils/index.ts | 7 +- test/lib/next-modes/base.ts | 7 +- test/lib/next-modes/next-dev.ts | 3 +- test/lib/next-modes/next-start.ts | 6 +- .../ci-missing-typescript-deps/index.test.ts | 24 ++- test/production/create-next-app/utils.ts | 85 ++++++++-- .../graceful-shutdown/index.test.ts | 29 ++-- test/production/pnpm-support/index.test.ts | 156 +++++++++--------- .../rewrite-request-smuggling.test.ts | 16 +- .../required-server-files-app.test.ts | 61 +++---- .../required-server-files-i18n.test.ts | 90 +++++----- .../required-server-files.test.ts | 131 +++++++-------- 31 files changed, 686 insertions(+), 603 deletions(-) diff --git a/contributing/core/testing.md b/contributing/core/testing.md index 1b84f8a0fb5d..5657fac9eb58 100644 --- a/contributing/core/testing.md +++ b/contributing/core/testing.md @@ -105,12 +105,12 @@ we attempt to capture traces of the playwright run to make debugging the failure A test-trace artifact should be uploaded after the workflow completes which can be downloaded, unzipped, and then inspected with `pnpm playwright show-trace ./path/to/trace` -To attach the chrome debugger to next the easiest approach is to modify the `createNext` call in your test to pass `--inspect` to next. +To attach the chrome debugger to next the easiest approach is to modify the `nextTestSetup` call in your test to pass `--inspect` to next. ```js -const next = await createNext({ +const { next } = nextTestSetup({ ... - startArgs: =['--inspect'], + startArgs: ['--inspect'], }) ``` diff --git a/test/development/app-dir/create-next-app-default/create-next-app-default.test.ts b/test/development/app-dir/create-next-app-default/create-next-app-default.test.ts index 813eaafeedfa..f22858e8ce66 100644 --- a/test/development/app-dir/create-next-app-default/create-next-app-default.test.ts +++ b/test/development/app-dir/create-next-app-default/create-next-app-default.test.ts @@ -1,5 +1,6 @@ -import { createNext } from 'e2e-utils' -import { retry } from 'next-test-utils' +import { spawn } from 'child_process' +import { findPort, killApp, retry } from 'next-test-utils' +import webdriver from 'next-webdriver' import { join } from 'path' import { resolveNextTgzFilename, @@ -35,18 +36,64 @@ describe('create-next-app default template', () => { expect(exitCode).toBe(0) - const nextBin = 'node_modules/next/dist/bin/next' - const next = await createNext({ - files: join(cwd, projectName), - installCommand: 'true', - skipStart: false, - startCommand: `node ${nextBin} dev`, - startServerTimeout: 60_000, - }) - let browser: Awaited> | undefined + const dir = join(cwd, projectName) + const nextBin = join(dir, 'node_modules/next/dist/bin/next') + const port = await findPort() + const server = spawn( + 'node', + [nextBin, 'dev', '-p', String(port), '-H', '127.0.0.1'], + { + cwd: dir, + env: { ...process.env, HOSTNAME: '127.0.0.1' }, + stdio: ['ignore', 'pipe', 'pipe'], + } + ) + + // Freshly installed CNA projects (with tailwind, eslint plugins, etc.) + // can take well over the default 10s to boot `next dev`. Give them + // generous headroom so this test isn't flaky on loaded CI machines. + const startServerTimeout = 60_000 + + let browser: Awaited> | undefined try { - browser = await next.browser('/') + await new Promise((resolve, reject) => { + const onTimeout = setTimeout(() => { + reject( + new Error( + `next dev did not become ready within ${startServerTimeout}ms` + ) + ) + }, startServerTimeout) + + const onReady = () => { + clearTimeout(onTimeout) + resolve() + } + + const handleData = (chunk: Buffer) => { + const msg = chunk.toString() + process.stdout.write(msg) + if (/- Local:|Ready in|✓ Ready/i.test(msg)) { + onReady() + } + } + + server.stdout!.on('data', handleData) + server.stderr!.on('data', (chunk: Buffer) => { + process.stderr.write(chunk.toString()) + }) + server.on('exit', (code) => { + clearTimeout(onTimeout) + reject( + new Error( + `next dev exited before becoming ready (code=${code})` + ) + ) + }) + }) + + browser = await webdriver(port, '/') const page = browser expect(await page.elementByCss('body').text()).toContain('Deploy Now') @@ -59,13 +106,22 @@ describe('create-next-app default template', () => { expect(imagesReady).toBe(true) }) + // In dev, the browser may fire a "preloaded using link preload but + // not used within a few seconds from the window's load event" + // warning for next/font's woff2 files when the stylesheet that + // references them hasn't been applied by the time the browser's + // internal timer fires (relative to window.load). The font is in + // fact used moments later, so this is a benign timing race that + // doesn't reproduce reliably — filter it out. const messages = (await page.log()).filter( - (log) => log.source === 'warning' || log.source === 'error' + (log) => + (log.source === 'warning' || log.source === 'error') && + !/was preloaded using link preload but not used/.test(log.message) ) expect(messages).toEqual([]) } finally { await browser?.close() - await next.destroy() + await killApp(server).catch(() => {}) } }) }, diff --git a/test/development/app-dir/hmr-asset-prefix-full-url/asset-prefix.test.ts b/test/development/app-dir/hmr-asset-prefix-full-url/asset-prefix.test.ts index 42bb67e99d42..ee490ef58d3e 100644 --- a/test/development/app-dir/hmr-asset-prefix-full-url/asset-prefix.test.ts +++ b/test/development/app-dir/hmr-asset-prefix-full-url/asset-prefix.test.ts @@ -1,20 +1,21 @@ -import { createNext } from 'e2e-utils' -import { findPort, retry } from 'next-test-utils' +import { nextTestSetup } from 'e2e-utils' +import { retry } from 'next-test-utils' describe('app-dir assetPrefix full URL', () => { - let next, forcedPort - beforeAll(async () => { - forcedPort = ((await findPort()) ?? '54321').toString() + const { next } = nextTestSetup({ + files: __dirname, + skipStart: true, + forcedPort: 'random', + }) - next = await createNext({ - files: __dirname, - forcedPort, - nextConfig: { - assetPrefix: `http://localhost:${forcedPort}`, - }, - }) + beforeAll(async () => { + const port = next.forcedPort + await next.patchFile( + 'next.config.js', + `module.exports = { assetPrefix: 'http://localhost:${port}' }` + ) + await next.start() }) - afterAll(() => next.destroy()) it('should not break HMR when asset prefix set to full URL', async () => { const browser = await next.browser('/') diff --git a/test/development/app-hmr/server-restart.test.ts b/test/development/app-hmr/server-restart.test.ts index be2e3b6ba799..b2c87ddddb03 100644 --- a/test/development/app-hmr/server-restart.test.ts +++ b/test/development/app-hmr/server-restart.test.ts @@ -1,4 +1,4 @@ -import { FileRef, nextTestSetup, createNext } from 'e2e-utils' +import { FileRef, nextTestSetup } from 'e2e-utils' import { retry, waitFor } from 'next-test-utils' import path from 'path' @@ -6,6 +6,7 @@ describe('app-dir server restart', () => { const { next } = nextTestSetup({ files: new FileRef(path.join(__dirname, 'fixtures', 'default-template')), patchFileDelay: 1000, + forcedPort: 'random', }) it('should reload the page when the server restarts', async () => { @@ -34,15 +35,11 @@ describe('app-dir server restart', () => { }) }) - const appPort = next.appPort - await next.destroy() + await next.stop() - // Start a new server instance on the same port - const secondNext = await createNext({ - files: new FileRef(path.join(__dirname, 'fixtures', 'default-template')), - env: next.env, - forcedPort: appPort, - }) + // Start a new server instance on the same port (forcedPort: 'random' was + // resolved to a concrete port in setup() so next.start() reuses it). + await next.start() // Wait for the new server to be ready await waitFor(1000) @@ -60,7 +57,5 @@ describe('app-dir server restart', () => { await retry(async () => { expect(await browser.elementById('counter-value').text()).toBe('Count: 0') }) - - await secondNext.destroy() }) }) diff --git a/test/development/basic/hmr/run-basic-hmr-test.util.ts b/test/development/basic/hmr/run-basic-hmr-test.util.ts index 76589dd2e2a2..e8f08381d7b0 100644 --- a/test/development/basic/hmr/run-basic-hmr-test.util.ts +++ b/test/development/basic/hmr/run-basic-hmr-test.util.ts @@ -4,7 +4,7 @@ import { retry, waitFor, } from 'next-test-utils' -import { createNext, nextTestSetup } from 'e2e-utils' +import { nextTestSetup } from 'e2e-utils' export function runBasicHmrTest(nextConfig: { basePath: string @@ -14,6 +14,7 @@ export function runBasicHmrTest(nextConfig: { files: __dirname, nextConfig, patchFileDelay: 500, + forcedPort: 'random', }) const { basePath } = nextConfig @@ -90,7 +91,7 @@ export function runBasicHmrTest(nextConfig: { ) }) - await next.destroy() + await next.stop() let reloadPromise = new Promise((resolve) => { browser.on('request', (req) => { @@ -100,13 +101,8 @@ export function runBasicHmrTest(nextConfig: { }) }) - const secondNext = await createNext({ - files: __dirname, - nextConfig, - forcedPort: next.appPort, - }) + await next.start() await reloadPromise - await secondNext.destroy() }) } diff --git a/test/development/basic/next-rs-api.test.ts b/test/development/basic/next-rs-api.test.ts index 4303dd78e3d6..c9a6822fd4e6 100644 --- a/test/development/basic/next-rs-api.test.ts +++ b/test/development/basic/next-rs-api.test.ts @@ -1,5 +1,4 @@ -import { NextInstance, createNext } from 'e2e-utils' -import { trace } from 'next/dist/trace' +import { nextTestSetup } from 'e2e-utils' import { PHASE_DEVELOPMENT_SERVER } from 'next/constants' import { createDefineEnv, loadBindings, HmrTarget } from 'next/dist/build/swc' import type { @@ -121,39 +120,33 @@ export default () =>
${text}
;` } describe('next.rs api writeToDisk multiple times', () => { - let next: NextInstance - afterEach(async () => { - await next?.destroy() - }) - it('should allow to write to disk multiple times', async () => { - next = await createNext({ - skipStart: true, - files: { - 'pages/index.js': pagesIndexCode('hello world'), - 'lib/props.js': 'export default {}', - 'pages/page-nodejs.js': 'export default () =>
hello world
', - 'pages/page-edge.js': - 'export default () =>
hello world
\nexport const config = { runtime: "experimental-edge" }', - 'pages/api/nodejs.js': - 'export default () => Response.json({ hello: "world" })', - 'pages/api/edge.js': - 'export default () => Response.json({ hello: "world" })\nexport const config = { runtime: "edge" }', - 'app/layout.tsx': - 'export default function RootLayout({ children }: { children: any }) { return ({children})}', - 'app/loading.tsx': - 'export default function Loading() { return <>Loading }', - 'app/app/page.tsx': appPageCode('hello world'), - 'app/app/client.tsx': - '"use client";\nexport default () =>
hello world
', - 'app/app-edge/page.tsx': - 'export default () =>
hello world
\nexport const runtime = "edge"', - 'app/app-nodejs/page.tsx': - 'export default () =>
hello world
', - 'app/route-nodejs/route.ts': - 'export function GET() { return Response.json({ hello: "world" }) }', - 'app/route-edge/route.ts': - 'export function GET() { return Response.json({ hello: "world" }) }\nexport const runtime = "edge"', - 'server.js': ` + const { next } = nextTestSetup({ + skipStart: true, + files: { + 'pages/index.js': pagesIndexCode('hello world'), + 'lib/props.js': 'export default {}', + 'pages/page-nodejs.js': 'export default () =>
hello world
', + 'pages/page-edge.js': + 'export default () =>
hello world
\nexport const config = { runtime: "experimental-edge" }', + 'pages/api/nodejs.js': + 'export default () => Response.json({ hello: "world" })', + 'pages/api/edge.js': + 'export default () => Response.json({ hello: "world" })\nexport const config = { runtime: "edge" }', + 'app/layout.tsx': + 'export default function RootLayout({ children }: { children: any }) { return ({children})}', + 'app/loading.tsx': + 'export default function Loading() { return <>Loading }', + 'app/app/page.tsx': appPageCode('hello world'), + 'app/app/client.tsx': + '"use client";\nexport default () =>
hello world
', + 'app/app-edge/page.tsx': + 'export default () =>
hello world
\nexport const runtime = "edge"', + 'app/app-nodejs/page.tsx': 'export default () =>
hello world
', + 'app/route-nodejs/route.ts': + 'export function GET() { return Response.json({ hello: "world" }) }', + 'app/route-edge/route.ts': + 'export function GET() { return Response.json({ hello: "world" }) }\nexport const runtime = "edge"', + 'server.js': ` process.title = 'next.rs api run test'; const path = require('path'); const { PHASE_DEVELOPMENT_SERVER } = require('next/constants'); @@ -263,9 +256,10 @@ main() }); `, - }, - }) + }, + }) + it('should allow to write to disk multiple times', async () => { const result = spawnSync( 'node', ['--expose-gc', join(next.testDir, 'server.js')], @@ -281,41 +275,34 @@ main() }) describe('next.rs api', () => { - let next: NextInstance - beforeAll(async () => { - await trace('setup next instance').traceAsyncFn(async (rootSpan) => { - next = await createNext({ - skipStart: true, - files: { - 'pages/index.js': pagesIndexCode('hello world'), - 'lib/props.js': 'export default {}', - 'pages/page-nodejs.js': 'export default () =>
hello world
', - 'pages/page-edge.js': - 'export default () =>
hello world
\nexport const config = { runtime: "experimental-edge" }', - 'pages/api/nodejs.js': - 'export default () => Response.json({ hello: "world" })', - 'pages/api/edge.js': - 'export default () => Response.json({ hello: "world" })\nexport const config = { runtime: "edge" }', - 'app/layout.tsx': - 'export default function RootLayout({ children }: { children: any }) { return ({children})}', - 'app/loading.tsx': - 'export default function Loading() { return <>Loading }', - 'app/app/page.tsx': appPageCode('hello world'), - 'app/app/client.tsx': - '"use client";\nexport default () =>
hello world
', - 'app/app-edge/page.tsx': - 'export default () =>
hello world
\nexport const runtime = "edge"', - 'app/app-nodejs/page.tsx': - 'export default () =>
hello world
', - 'app/route-nodejs/route.ts': - 'export function GET() { return Response.json({ hello: "world" }) }', - 'app/route-edge/route.ts': - 'export function GET() { return Response.json({ hello: "world" }) }\nexport const runtime = "edge"', - }, - }) - }) + const { next } = nextTestSetup({ + skipStart: true, + files: { + 'pages/index.js': pagesIndexCode('hello world'), + 'lib/props.js': 'export default {}', + 'pages/page-nodejs.js': 'export default () =>
hello world
', + 'pages/page-edge.js': + 'export default () =>
hello world
\nexport const config = { runtime: "experimental-edge" }', + 'pages/api/nodejs.js': + 'export default () => Response.json({ hello: "world" })', + 'pages/api/edge.js': + 'export default () => Response.json({ hello: "world" })\nexport const config = { runtime: "edge" }', + 'app/layout.tsx': + 'export default function RootLayout({ children }: { children: any }) { return ({children})}', + 'app/loading.tsx': + 'export default function Loading() { return <>Loading }', + 'app/app/page.tsx': appPageCode('hello world'), + 'app/app/client.tsx': + '"use client";\nexport default () =>
hello world
', + 'app/app-edge/page.tsx': + 'export default () =>
hello world
\nexport const runtime = "edge"', + 'app/app-nodejs/page.tsx': 'export default () =>
hello world
', + 'app/route-nodejs/route.ts': + 'export function GET() { return Response.json({ hello: "world" }) }', + 'app/route-edge/route.ts': + 'export function GET() { return Response.json({ hello: "world" }) }\nexport const runtime = "edge"', + }, }) - afterAll(() => next.destroy()) let project: Project let projectUpdateSubscription: AsyncIterableIterator diff --git a/test/development/basic/project-directory-rename.test.ts b/test/development/basic/project-directory-rename.test.ts index ccb43a45a379..a42c7c82bc12 100644 --- a/test/development/basic/project-directory-rename.test.ts +++ b/test/development/basic/project-directory-rename.test.ts @@ -1,30 +1,26 @@ import fs from 'fs-extra' import webdriver from 'next-webdriver' -import { waitForNoRedbox, check, findPort } from 'next-test-utils' -import { NextInstance } from 'e2e-utils' -import { createNext } from 'e2e-utils' +import { waitForNoRedbox, check } from 'next-test-utils' +import { nextTestSetup } from 'e2e-utils' import stripAnsi from 'strip-ansi' // TODO: investigate occasional failure describe.skip('Project Directory Renaming', () => { - let next: NextInstance - - beforeAll(async () => { - next = await createNext({ - files: { - 'pages/index.js': ` + const { next } = nextTestSetup({ + files: { + 'pages/index.js': ` export default function Page() { return

hello world

} `, - }, - skipStart: true, - forcedPort: (await findPort()) + '', - }) + }, + skipStart: true, + forcedPort: 'random', + }) + beforeAll(async () => { await next.start() }) - afterAll(() => next.destroy().catch(() => {})) it('should detect project dir rename and restart', async () => { const browser = await webdriver(next.url, '/') diff --git a/test/development/start-no-build/start-no-build.test.ts b/test/development/start-no-build/start-no-build.test.ts index c5582e76399a..a1ab5ff56439 100644 --- a/test/development/start-no-build/start-no-build.test.ts +++ b/test/development/start-no-build/start-no-build.test.ts @@ -1,23 +1,21 @@ -import { createNext } from 'e2e-utils' +import { nextTestSetup } from 'e2e-utils' describe('next start without next build', () => { - it('should show error when there is no production build', async () => { - const next = await createNext({ - files: __dirname, - skipStart: true, - startCommand: `pnpm next start`, - serverReadyPattern: /Local:/, - }) + const { next } = nextTestSetup({ + files: __dirname, + skipStart: true, + startCommand: `pnpm next start`, + serverReadyPattern: /Local:/, + }) + it('should show error when there is no production build', async () => { await next.start() - await new Promise((resolve, reject) => { + await new Promise((resolve) => { next.on('stderr', (msg) => { if (msg.includes('Could not find a production build in the')) { resolve() } }) }) - - await next.destroy() }) }) diff --git a/test/e2e/app-dir/create-root-layout/create-root-layout.test.ts b/test/e2e/app-dir/create-root-layout/create-root-layout.test.ts index a9d9ec19e141..430e116dcd50 100644 --- a/test/e2e/app-dir/create-root-layout/create-root-layout.test.ts +++ b/test/e2e/app-dir/create-root-layout/create-root-layout.test.ts @@ -1,5 +1,5 @@ import path from 'path' -import { createNext, FileRef, nextTestSetup } from 'e2e-utils' +import { FileRef, nextTestSetup } from 'e2e-utils' import { check } from 'next-test-utils' import stripAnsi from 'strip-ansi' @@ -202,24 +202,23 @@ import stripAnsi from 'strip-ansi' }) } else { describe('build', () => { - it('should break the build if a page is missing root layout', async () => { - const next = await createNext({ - skipStart: true, - files: { - 'app/page.js': new FileRef( - path.join(__dirname, 'app/route/page.js') - ), - 'next.config.js': new FileRef( - path.join(__dirname, 'next.config.js') - ), - }, - }) + const { next } = nextTestSetup({ + skipStart: true, + files: { + 'app/page.js': new FileRef( + path.join(__dirname, 'app/route/page.js') + ), + 'next.config.js': new FileRef( + path.join(__dirname, 'next.config.js') + ), + }, + }) + it('should break the build if a page is missing root layout', async () => { await expect(next.start()).rejects.toThrow('next build failed') expect(stripAnsi(next.cliOutput)).toInclude( "page.js doesn't have a root layout. To fix this error, make sure every page has a root layout." ) - await next.destroy() }) }) } diff --git a/test/e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts b/test/e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts index 668ec28b13bd..2e989e52e235 100644 --- a/test/e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts +++ b/test/e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts @@ -1,4 +1,4 @@ -import { createNext } from 'e2e-utils' +import { nextTestSetup } from 'e2e-utils' import { findPort } from 'next-test-utils' import { createTestDataServer } from 'test-data-service/writer' import { createTestLog } from 'test-log' @@ -11,10 +11,13 @@ describe('avoid-popstate-flash', () => { return } + const { next } = nextTestSetup({ + files: __dirname, + skipStart: true, + }) + let server - let next - afterEach(async () => { - await next?.destroy() + afterEach(() => { server?.close() }) @@ -35,10 +38,8 @@ describe('avoid-popstate-flash', () => { }) const port = await findPort() server.listen(port) - next = await createNext({ - files: __dirname, - env: { TEST_DATA_SERVICE_URL: `http://localhost:${port}` }, - }) + next.env.TEST_DATA_SERVICE_URL = `http://localhost:${port}` + await next.start() TestLog.assert(['REQUEST: Static']) autoresolveRequests = false diff --git a/test/e2e/app-dir/ppr-navigations/search-params/search-params.test.ts b/test/e2e/app-dir/ppr-navigations/search-params/search-params.test.ts index ffdc2a131900..d4ff26780312 100644 --- a/test/e2e/app-dir/ppr-navigations/search-params/search-params.test.ts +++ b/test/e2e/app-dir/ppr-navigations/search-params/search-params.test.ts @@ -1,4 +1,4 @@ -import { createNext } from 'e2e-utils' +import { nextTestSetup } from 'e2e-utils' // TODO(NAR-423): Migrate to Cache Components. describe.skip('search-params', () => { @@ -7,20 +7,14 @@ describe.skip('search-params', () => { return } - let server - let next - afterEach(async () => { - await next?.destroy() - server?.close() + const { next } = nextTestSetup({ + files: __dirname, }) test( 'updates page data during a nav even if no shared layouts have changed ' + '(e.g. updating a search param on the current page)', async () => { - next = await createNext({ - files: __dirname, - }) const browser = await next.browser('/') // Click a link that updates the current page's search params. diff --git a/test/e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts b/test/e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts index 33b0c8438993..1edbd0ef7e9f 100644 --- a/test/e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts +++ b/test/e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts @@ -1,4 +1,4 @@ -import { createNext } from 'e2e-utils' +import { nextTestSetup } from 'e2e-utils' import { findPort } from 'next-test-utils' import { createTestDataServer } from 'test-data-service/writer' import { createTestLog } from 'test-log' @@ -11,10 +11,13 @@ describe('stale-prefetch-entry', () => { return } + const { next } = nextTestSetup({ + files: __dirname, + skipStart: true, + }) + let server - let next - afterEach(async () => { - await next?.destroy() + afterEach(() => { server?.close() }) @@ -42,10 +45,8 @@ describe('stale-prefetch-entry', () => { }) const port = await findPort() server.listen(port) - next = await createNext({ - files: __dirname, - env: { TEST_DATA_SERVICE_URL: `http://localhost:${port}` }, - }) + next.env.TEST_DATA_SERVICE_URL = `http://localhost:${port}` + await next.start() TestLog.assert(['REQUEST: Some data [static]']) autoresolveRequests = false diff --git a/test/e2e/app-dir/ppr-unstable-cache/ppr-unstable-cache.test.ts b/test/e2e/app-dir/ppr-unstable-cache/ppr-unstable-cache.test.ts index 184415368942..dc2d48ee4dad 100644 --- a/test/e2e/app-dir/ppr-unstable-cache/ppr-unstable-cache.test.ts +++ b/test/e2e/app-dir/ppr-unstable-cache/ppr-unstable-cache.test.ts @@ -1,4 +1,4 @@ -import { NextInstance, createNext, isNextDeploy, isNextDev } from 'e2e-utils' +import { nextTestSetup, isNextDeploy, isNextDev } from 'e2e-utils' import { findPort } from 'next-test-utils' import http from 'node:http' @@ -13,14 +13,13 @@ describe('ppr-unstable-cache', () => { return } - let next: NextInstance | null = null + const { next } = nextTestSetup({ + files: __dirname, + skipStart: true, + }) + let server: http.Server | null = null afterEach(async () => { - if (next) { - await next.destroy() - next = null - } - if (server) { await server.close() server = null @@ -48,10 +47,8 @@ describe('ppr-unstable-cache', () => { const port = await findPort() server.listen(port) - next = await createNext({ - files: __dirname, - env: { TEST_DATA_SERVER: `http://localhost:${port}/` }, - }) + next.env.TEST_DATA_SERVER = `http://localhost:${port}/` + await next.start() expect(generations).toHaveLength(2) diff --git a/test/e2e/app-dir/segment-cache/revalidation/segment-cache-revalidation.test.ts b/test/e2e/app-dir/segment-cache/revalidation/segment-cache-revalidation.test.ts index 100a46dbd58b..4611cc179023 100644 --- a/test/e2e/app-dir/segment-cache/revalidation/segment-cache-revalidation.test.ts +++ b/test/e2e/app-dir/segment-cache/revalidation/segment-cache-revalidation.test.ts @@ -1,5 +1,5 @@ import type * as Playwright from 'playwright' -import { isNextDev, isNextDeploy, createNext } from 'e2e-utils' +import { isNextDev, isNextDeploy, nextTestSetup } from 'e2e-utils' import { createRouterAct } from 'router-act' import { createTestDataServer } from 'test-data-service/writer' import { createTestLog } from 'test-log' @@ -16,7 +16,11 @@ describe('segment cache (revalidation)', () => { let dataVersions = new Map() let TestLog = createTestLog() - let next + const { next } = nextTestSetup({ + files: __dirname, + skipStart: true, + }) + beforeAll(async () => { port = await findPort() server = createTestDataServer(async (key, res) => { @@ -34,10 +38,8 @@ describe('segment cache (revalidation)', () => { }) server.listen(port) - next = await createNext({ - files: __dirname, - env: { TEST_DATA_SERVICE_URL: `http://localhost:${port}` }, - }) + next.env.TEST_DATA_SERVICE_URL = `http://localhost:${port}` + await next.start() }) beforeEach(async () => { @@ -46,7 +48,6 @@ describe('segment cache (revalidation)', () => { }) afterAll(async () => { - await next?.destroy() server?.close() }) diff --git a/test/e2e/next-font/with-proxy.test.ts b/test/e2e/next-font/with-proxy.test.ts index 0d781f7cf9e4..09743d791892 100644 --- a/test/e2e/next-font/with-proxy.test.ts +++ b/test/e2e/next-font/with-proxy.test.ts @@ -1,21 +1,24 @@ -import { FileRef, createNext, NextInstance } from 'e2e-utils' +import { FileRef, nextTestSetup } from 'e2e-utils' import { findPort, renderViaHTTP, fetchViaHTTP } from 'next-test-utils' import { join } from 'path' import spawn from 'cross-spawn' describe('next/font/google with proxy', () => { - let next: NextInstance - let proxy: any - let PROXY_PORT: number - let SERVER_PORT: number - if ((global as any).isNextDeploy) { it('should skip next deploy', () => {}) return } + const { next } = nextTestSetup({ + files: new FileRef(join(__dirname, 'with-proxy')), + skipStart: true, + }) + + let proxy: any + let SERVER_PORT: number + beforeAll(async () => { - PROXY_PORT = await findPort() + const PROXY_PORT = await findPort() SERVER_PORT = await findPort() proxy = spawn('node', [require.resolve('./with-proxy/server.js')], { @@ -27,16 +30,12 @@ describe('next/font/google with proxy', () => { }, }) - next = await createNext({ - files: new FileRef(join(__dirname, 'with-proxy')), - env: { - http_proxy: 'http://localhost:' + PROXY_PORT, - }, + await next.start({ + env: { http_proxy: 'http://localhost:' + PROXY_PORT }, }) }) - afterAll(async () => { - await next.destroy() - proxy.kill('SIGKILL') + afterAll(() => { + proxy?.kill('SIGKILL') }) // Reqwest doesn't seem to fully work with https proxy diff --git a/test/e2e/next-script/index.test.ts b/test/e2e/next-script/index.test.ts index a3c73d6cd3a7..2776fd46e948 100644 --- a/test/e2e/next-script/index.test.ts +++ b/test/e2e/next-script/index.test.ts @@ -1,6 +1,5 @@ import webdriver, { Playwright } from 'next-webdriver' -import { createNext, nextTestSetup } from 'e2e-utils' -import { NextInstance } from 'e2e-utils' +import { nextTestSetup } from 'e2e-utils' import { check } from 'next-test-utils' describe('beforeInteractive in document Head', () => { @@ -321,28 +320,8 @@ describe('empty strategy in document body', () => { }) }) - describe('experimental.nextScriptWorkers: true with required Partytown dependency for inline script', () => { - let next: NextInstance - - // Note: previously we were using `finally` cluase inside of test assertion. However, if the test times out - // exceeding jest.setTimeout() value, the finally clause is not executed and subsequent tests will fail due to - // hanging next instance. - afterEach(async () => { - if (next) { - await next.destroy() - next = undefined - } - }) - - const createNextApp = async (script) => - await createNext({ - nextConfig: { - experimental: { - nextScriptWorkers: true, - }, - }, - files: { - 'pages/index.js': ` + function buildInlineScriptPage(script: string) { + return ` import Script from 'next/script' export default function Page() { @@ -353,20 +332,29 @@ describe('empty strategy in document body', () => { ) } - `, - }, - dependencies: { - '@builder.io/partytown': '0.4.2', + ` + } + + describe('experimental.nextScriptWorkers: true with required Partytown dependency for inline script (children)', () => { + const { next } = nextTestSetup({ + nextConfig: { + experimental: { + nextScriptWorkers: true, }, - }) + }, + files: { + 'pages/index.js': buildInlineScriptPage( + `` + ), + }, + dependencies: { + '@builder.io/partytown': '0.4.2', + }, + }) it('Inline worker script through children is modified by Partytown to execute on a worker thread', async () => { let browser: Playwright - next = await createNextApp( - `` - ) - try { browser = await webdriver(next.url, '/') @@ -384,14 +372,28 @@ describe('empty strategy in document body', () => { if (browser) await browser.close() } }) + }) + + describe('experimental.nextScriptWorkers: true with required Partytown dependency for inline script (dangerouslySetInnerHTML)', () => { + const { next } = nextTestSetup({ + nextConfig: { + experimental: { + nextScriptWorkers: true, + }, + }, + files: { + 'pages/index.js': buildInlineScriptPage( + `