diff --git a/src/build/content/server.ts b/src/build/content/server.ts
index 8aa2287be4..ffa5dbbd4c 100644
--- a/src/build/content/server.ts
+++ b/src/build/content/server.ts
@@ -106,7 +106,7 @@ export const copyNextServerCode = async (ctx: PluginContext): Promise => {
`server/*`,
`server/chunks/**/*`,
`server/edge-chunks/**/*`,
- `server/edge/chunks/**/*`,
+ `server/edge/**/*`,
`server/+(app|pages)/**/*.js`,
],
{
@@ -291,6 +291,8 @@ async function patchNextModules(
export const copyNextDependencies = async (ctx: PluginContext): Promise => {
await tracer.withActiveSpan('copyNextDependencies', async () => {
const entries = await readdir(ctx.standaloneDir)
+ const filter = ctx.constants.IS_LOCAL ? undefined : nodeModulesFilter
+
const promises: Promise[] = entries.map(async (entry) => {
// copy all except the distDir (.next) folder as this is handled in a separate function
// this will include the node_modules folder as well
@@ -299,7 +301,6 @@ export const copyNextDependencies = async (ctx: PluginContext): Promise =>
}
const src = join(ctx.standaloneDir, entry)
const dest = join(ctx.serverHandlerDir, entry)
- const filter = ctx.constants.IS_LOCAL ? undefined : nodeModulesFilter
await cp(src, dest, {
recursive: true,
verbatimSymlinks: true,
@@ -321,7 +322,7 @@ export const copyNextDependencies = async (ctx: PluginContext): Promise =>
// see: https://github.com/vercel/next.js/issues/50072
if (existsSync(rootSrcDir) && ctx.standaloneRootDir !== ctx.standaloneDir) {
promises.push(
- cp(rootSrcDir, rootDestDir, { recursive: true, verbatimSymlinks: true }).then(() =>
+ cp(rootSrcDir, rootDestDir, { recursive: true, verbatimSymlinks: true, filter }).then(() =>
recreateNodeModuleSymlinks(resolve('node_modules'), rootDestDir),
),
)
diff --git a/tests/e2e/cli-before-regional-blobs-support.test.ts b/tests/e2e/cli-before-regional-blobs-support.test.ts
index e4779339f8..c6f7193e01 100644
--- a/tests/e2e/cli-before-regional-blobs-support.test.ts
+++ b/tests/e2e/cli-before-regional-blobs-support.test.ts
@@ -17,7 +17,7 @@ test('should serve 404 page when requesting non existing page (no matching route
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('h1')).toBe('404')
+ await expect(page.locator('h1')).toHaveText('404')
// https://github.com/vercel/next.js/pull/69802 made changes to returned cache-control header,
// after that (14.2.10 and canary.147) 404 pages would have `private` directive, before that it
diff --git a/tests/e2e/middleware.test.ts b/tests/e2e/middleware.test.ts
index a25de675a4..369d65f2a1 100644
--- a/tests/e2e/middleware.test.ts
+++ b/tests/e2e/middleware.test.ts
@@ -246,6 +246,11 @@ for (const { expectedRuntime, isNodeMiddleware, label, testWithSwitchableMiddlew
const pageResponse = await page.goto(`${edgeOrNodeMiddlewarePages.url}/link`)
expect(await pageResponse?.headerValue('x-runtime')).toEqual(expectedRuntime)
+ // wait for hydration to finish before doing client navigation
+ await expect(page.getByTestId('hydration')).toHaveText('hydrated', {
+ timeout: 10_000,
+ })
+
await page.evaluate(() => {
// set some value to window to check later if browser did reload and lost this state
;(window as ExtendedWindow).didReload = false
@@ -305,6 +310,11 @@ for (const { expectedRuntime, isNodeMiddleware, label, testWithSwitchableMiddlew
)
expect(await pageResponse?.headerValue('x-runtime')).toEqual(expectedRuntime)
+ // wait for hydration to finish before doing client navigation
+ await expect(page.getByTestId('hydration')).toHaveText('hydrated', {
+ timeout: 10_000,
+ })
+
await page.evaluate(() => {
// set some value to window to check later if browser did reload and lost this state
;(window as ExtendedWindow).didReload = false
diff --git a/tests/e2e/on-demand-app.test.ts b/tests/e2e/on-demand-app.test.ts
index 13c0ee3dd2..b4e6ea63aa 100644
--- a/tests/e2e/on-demand-app.test.ts
+++ b/tests/e2e/on-demand-app.test.ts
@@ -96,9 +96,9 @@ test.describe('app router on-demand revalidation', () => {
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
)
- const date1 = await page.textContent('[data-testid="date-now"]')
+ const date1 = await page.getByTestId('date-now').textContent()
- const h1 = await page.textContent('h1')
+ const h1 = await page.locator('h1').textContent()
expect(h1).toBe(expectedH1Content)
const response2 = await pollUntilHeadersMatch(new URL(pagePath, serverComponents.url).href, {
@@ -127,7 +127,7 @@ test.describe('app router on-demand revalidation', () => {
)
// the page is cached
- const date2 = await page.textContent('[data-testid="date-now"]')
+ const date2 = await page.getByTestId('date-now').textContent()
expect(date2).toBe(date1)
const revalidate = await page.goto(new URL(revalidateApiPath, serverComponents.url).href)
@@ -159,7 +159,7 @@ test.describe('app router on-demand revalidation', () => {
)
// the page has now an updated date
- const date3 = await page.textContent('[data-testid="date-now"]')
+ const date3 = await page.getByTestId('date-now').textContent()
expect(date3).not.toBe(date2)
const response4 = await pollUntilHeadersMatch(new URL(pagePath, serverComponents.url).href, {
@@ -188,7 +188,7 @@ test.describe('app router on-demand revalidation', () => {
)
// the page is cached
- const date4 = await page.textContent('[data-testid="date-now"]')
+ const date4 = await page.getByTestId('date-now').textContent()
expect(date4).toBe(date3)
})
}
diff --git a/tests/e2e/page-router.test.ts b/tests/e2e/page-router.test.ts
index d0c8f2ee11..759928c7b2 100644
--- a/tests/e2e/page-router.test.ts
+++ b/tests/e2e/page-router.test.ts
@@ -174,12 +174,12 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
)
if (fallbackWasServed) {
- const loading = await page.textContent('[data-testid="loading"]')
+ const loading = await page.getByTestId('loading').textContent()
expect(loading, 'Fallback should be shown').toBe('Loading...')
}
- const date1 = await page.textContent('[data-testid="date-now"]')
- const h1 = await page.textContent('h1')
+ const date1 = await page.getByTestId('date-now').textContent()
+ const h1 = await page.locator('h1').textContent()
expect(h1).toBe(expectedH1Content)
// check json route
@@ -238,7 +238,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
)
// the page is cached
- const date2 = await page.textContent('[data-testid="date-now"]')
+ const date2 = await page.getByTestId('date-now').textContent()
expect(date2).toBe(date1)
// check json route
@@ -299,7 +299,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date3 = await page.textContent('[data-testid="date-now"]')
+ const date3 = await page.getByTestId('date-now').textContent()
expect(date3).not.toBe(date2)
// check json route
@@ -366,7 +366,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
},
)
expect(response1?.status()).toBe(200)
- const date1 = (await page.textContent('[data-testid="date-now"]')) ?? ''
+ const date1 = (await page.getByTestId('date-now').textContent()) ?? ''
// ensure response was produced before invocation (served from cache)
expect(date1.localeCompare(beforeFetch)).toBeLessThan(0)
@@ -391,7 +391,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
},
)
expect(response2?.status()).toBe(200)
- const date2 = (await page.textContent('[data-testid="date-now"]')) ?? ''
+ const date2 = (await page.getByTestId('date-now').textContent()) ?? ''
// ensure response was produced after initial invocation
expect(beforeFetch.localeCompare(date2)).toBeLessThan(0)
@@ -416,7 +416,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
)
// ensure response was NOT produced before invocation
- const date1 = (await page.textContent('[data-testid="date-now"]')) ?? ''
+ const date1 = (await page.getByTestId('date-now').textContent()) ?? ''
expect(date1.localeCompare(beforeFirstFetch)).toBeGreaterThan(0)
// allow page to get stale
@@ -431,7 +431,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
/s-maxage=60, stale-while-revalidate=[0-9]+, durable/,
)
- const date2 = (await page.textContent('[data-testid="date-now"]')) ?? ''
+ const date2 = (await page.getByTestId('date-now').textContent()) ?? ''
expect(date2).toBe(date1)
// wait a bit to ensure background work has a chance to finish
@@ -450,7 +450,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
/s-maxage=60, stale-while-revalidate=[0-9]+, durable/,
)
- const date3 = (await page.textContent('[data-testid="date-now"]')) ?? ''
+ const date3 = (await page.getByTestId('date-now').textContent()) ?? ''
expect(date3.localeCompare(date2)).toBeGreaterThan(0)
})
@@ -469,7 +469,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('p')).toBe('Custom 404 page')
+ await expect(page.getByTestId('custom-404')).toHaveText('Custom 404 page')
// https://github.com/vercel/next.js/pull/69802 made changes to returned cache-control header,
// after that (14.2.10 and canary.147) 404 pages would have `private` directive, before that
@@ -493,7 +493,7 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('p')).toBe('Custom 404 page')
+ await expect(page.getByTestId('custom-404')).toHaveText('Custom 404 page')
expect(headers['debug-netlify-cdn-cache-control']).toBe(
nextVersionSatisfies('>=15.0.0-canary.187')
@@ -748,12 +748,12 @@ test.describe('Page Router with basePath and i18n', () => {
)
if (fallbackWasServedImplicitLocale) {
- const loading = await page.textContent('[data-testid="loading"]')
+ const loading = await page.getByTestId('loading').textContent()
expect(loading, 'Fallback should be shown').toBe('Loading...')
}
- const date1ImplicitLocale = await page.textContent('[data-testid="date-now"]')
- const h1ImplicitLocale = await page.textContent('h1')
+ const date1ImplicitLocale = await page.getByTestId('date-now').textContent()
+ const h1ImplicitLocale = await page.locator('h1').textContent()
expect(h1ImplicitLocale).toBe(expectedH1Content)
const response1ExplicitLocale = await pollUntilHeadersMatch(
@@ -790,12 +790,12 @@ test.describe('Page Router with basePath and i18n', () => {
)
if (fallbackWasServedExplicitLocale) {
- const loading = await page.textContent('[data-testid="loading"]')
+ const loading = await page.getByTestId('loading').textContent()
expect(loading, 'Fallback should be shown').toBe('Loading...')
}
- const date1ExplicitLocale = await page.textContent('[data-testid="date-now"]')
- const h1ExplicitLocale = await page.textContent('h1')
+ const date1ExplicitLocale = await page.getByTestId('date-now').textContent()
+ const h1ExplicitLocale = await page.locator('h1').textContent()
expect(h1ExplicitLocale).toBe(expectedH1Content)
// implicit and explicit locale paths should be the same (same cached response)
@@ -861,7 +861,7 @@ test.describe('Page Router with basePath and i18n', () => {
)
// the page is cached
- const date2ImplicitLocale = await page.textContent('[data-testid="date-now"]')
+ const date2ImplicitLocale = await page.getByTestId('date-now').textContent()
expect(date2ImplicitLocale).toBe(date1ImplicitLocale)
const response2ExplicitLocale = await pollUntilHeadersMatch(
@@ -893,7 +893,7 @@ test.describe('Page Router with basePath and i18n', () => {
)
// the page is cached
- const date2ExplicitLocale = await page.textContent('[data-testid="date-now"]')
+ const date2ExplicitLocale = await page.getByTestId('date-now').textContent()
expect(date2ExplicitLocale).toBe(date1ExplicitLocale)
// check json route
@@ -961,7 +961,7 @@ test.describe('Page Router with basePath and i18n', () => {
expect(headers3ImplicitLocale?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date3ImplicitLocale = await page.textContent('[data-testid="date-now"]')
+ const date3ImplicitLocale = await page.getByTestId('date-now').textContent()
expect(date3ImplicitLocale).not.toBe(date2ImplicitLocale)
const response3ExplicitLocale = await pollUntilHeadersMatch(
@@ -984,7 +984,7 @@ test.describe('Page Router with basePath and i18n', () => {
expect(headers3ExplicitLocale?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date3ExplicitLocale = await page.textContent('[data-testid="date-now"]')
+ const date3ExplicitLocale = await page.getByTestId('date-now').textContent()
expect(date3ExplicitLocale).not.toBe(date2ExplicitLocale)
// implicit and explicit locale paths should be the same (same cached response)
@@ -1057,7 +1057,7 @@ test.describe('Page Router with basePath and i18n', () => {
expect(headers4ImplicitLocale?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date4ImplicitLocale = await page.textContent('[data-testid="date-now"]')
+ const date4ImplicitLocale = await page.getByTestId('date-now').textContent()
expect(date4ImplicitLocale).not.toBe(date3ImplicitLocale)
const response4ExplicitLocale = await pollUntilHeadersMatch(
@@ -1080,7 +1080,7 @@ test.describe('Page Router with basePath and i18n', () => {
expect(headers4ExplicitLocale?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date4ExplicitLocale = await page.textContent('[data-testid="date-now"]')
+ const date4ExplicitLocale = await page.getByTestId('date-now').textContent()
expect(date4ExplicitLocale).not.toBe(date3ExplicitLocale)
// implicit and explicit locale paths should be the same (same cached response)
@@ -1173,12 +1173,12 @@ test.describe('Page Router with basePath and i18n', () => {
)
if (fallbackWasServed) {
- const loading = await page.textContent('[data-testid="loading"]')
+ const loading = await page.getByTestId('loading').textContent()
expect(loading, 'Fallback should be shown').toBe('Loading...')
}
- const date1 = await page.textContent('[data-testid="date-now"]')
- const h1 = await page.textContent('h1')
+ const date1 = await page.getByTestId('date-now').textContent()
+ const h1 = await page.locator('h1').textContent()
expect(h1).toBe(expectedH1Content)
// check json route
@@ -1241,7 +1241,7 @@ test.describe('Page Router with basePath and i18n', () => {
)
// the page is cached
- const date2 = await page.textContent('[data-testid="date-now"]')
+ const date2 = await page.getByTestId('date-now').textContent()
expect(date2).toBe(date1)
// check json route
@@ -1309,7 +1309,7 @@ test.describe('Page Router with basePath and i18n', () => {
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date3 = await page.textContent('[data-testid="date-now"]')
+ const date3 = await page.getByTestId('date-now').textContent()
expect(date3).not.toBe(date2)
// check json route
@@ -1360,7 +1360,7 @@ test.describe('Page Router with basePath and i18n', () => {
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('p')).toBe('Custom 404 page for locale: en')
+ await expect(page.getByTestId('custom-404')).toHaveText('Custom 404 page for locale: en')
expect(headers['debug-netlify-cdn-cache-control']).toMatch(
/no-cache, no-store, max-age=0, must-revalidate, durable/m,
@@ -1378,7 +1378,7 @@ test.describe('Page Router with basePath and i18n', () => {
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('p')).toBe('Custom 404 page for locale: en')
+ await expect(page.getByTestId('custom-404')).toHaveText('Custom 404 page for locale: en')
// Prior to v14.2.4 notFound pages are not cacheable
// https://github.com/vercel/next.js/pull/66674
diff --git a/tests/e2e/simple-app.test.ts b/tests/e2e/simple-app.test.ts
index fb790afcff..c9b4aea017 100644
--- a/tests/e2e/simple-app.test.ts
+++ b/tests/e2e/simple-app.test.ts
@@ -1,5 +1,5 @@
import { expect, type Locator, type Response } from '@playwright/test'
-import { nextVersionSatisfies } from '../utils/next-version-helpers.mjs'
+import { hasDefaultTurbopackBuilds, nextVersionSatisfies } from '../utils/next-version-helpers.mjs'
import { test } from '../utils/playwright-helpers.js'
const expectImageWasLoaded = async (locator: Locator) => {
@@ -227,7 +227,7 @@ test('requesting a non existing page route that needs to be fetched from the blo
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('h1')).toBe('404 Not Found')
+ await expect(page.locator('h1')).toHaveText('404 Not Found')
// https://github.com/vercel/next.js/pull/66674 made changes to returned cache-control header,
// before that 404 page would have `private` directive, after that (14.2.4 and canary.24) it
@@ -254,7 +254,7 @@ test('requesting a non existing page route that needs to be fetched from the blo
const headers = response?.headers() || {}
expect(response?.status()).toBe(404)
- expect(await page.textContent('h1')).toBe('404 Not Found')
+ await expect(page.locator('h1')).toHaveText('404 Not Found')
expect(headers['debug-netlify-cdn-cache-control']).toBe(
nextVersionSatisfies('>=15.0.0-canary.187')
@@ -273,6 +273,8 @@ test('Compressed rewrites are readable', async ({ simple }) => {
})
test('can require CJS module that is not bundled', async ({ simple }) => {
+ // setup for this test only works with webpack builds due to usage of ` __non_webpack_require__` to avoid bundling a file
+ test.skip(hasDefaultTurbopackBuilds(), 'Setup for this test only works with webpack builds')
const resp = await fetch(`${simple.url}/api/cjs-file-with-js-extension`)
expect(resp.status).toBe(200)
diff --git a/tests/e2e/turborepo.test.ts b/tests/e2e/turborepo.test.ts
index 0475994571..e362536995 100644
--- a/tests/e2e/turborepo.test.ts
+++ b/tests/e2e/turborepo.test.ts
@@ -41,8 +41,8 @@ test.describe('[PNPM] Package manager', () => {
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
)
- const date1 = await page.textContent('[data-testid="date-now"]')
- const h1 = await page.textContent('h1')
+ const date1 = await page.getByTestId('date-now').textContent()
+ const h1 = await page.locator('h1').textContent()
expect(h1).toBe('Show #71')
const response2 = await pollUntilHeadersMatch(
@@ -74,7 +74,7 @@ test.describe('[PNPM] Package manager', () => {
)
// the page is cached
- const date2 = await page.textContent('[data-testid="date-now"]')
+ const date2 = await page.getByTestId('date-now').textContent()
expect(date2).toBe(date1)
const revalidate = await page.goto(new URL('/api/revalidate', turborepo.url).href)
@@ -104,7 +104,7 @@ test.describe('[PNPM] Package manager', () => {
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date3 = await page.textContent('[data-testid="date-now"]')
+ const date3 = await page.getByTestId('date-now').textContent()
expect(date3).not.toBe(date2)
})
})
@@ -149,8 +149,8 @@ test.describe('[NPM] Package manager', () => {
: 's-maxage=31536000, stale-while-revalidate=31536000, durable',
)
- const date1 = await page.textContent('[data-testid="date-now"]')
- const h1 = await page.textContent('h1')
+ const date1 = await page.getByTestId('date-now').textContent()
+ const h1 = await page.locator('h1').textContent()
expect(h1).toBe('Show #71')
const response2 = await pollUntilHeadersMatch(
@@ -182,7 +182,7 @@ test.describe('[NPM] Package manager', () => {
)
// the page is cached
- const date2 = await page.textContent('[data-testid="date-now"]')
+ const date2 = await page.getByTestId('date-now').textContent()
expect(date2).toBe(date1)
const revalidate = await page.goto(new URL('/api/revalidate', turborepoNPM.url).href)
@@ -212,7 +212,7 @@ test.describe('[NPM] Package manager', () => {
expect(headers3?.['x-nextjs-cache']).toBeUndefined()
// the page has now an updated date
- const date3 = await page.textContent('[data-testid="date-now"]')
+ const date3 = await page.getByTestId('date-now').textContent()
expect(date3).not.toBe(date2)
})
diff --git a/tests/fixtures/middleware-i18n/pages/link/index.js b/tests/fixtures/middleware-i18n/pages/link/index.js
index 73699d73a1..e0d58ba263 100644
--- a/tests/fixtures/middleware-i18n/pages/link/index.js
+++ b/tests/fixtures/middleware-i18n/pages/link/index.js
@@ -1,6 +1,12 @@
+import { useState, useEffect } from 'react'
import Link from 'next/link'
export default function Page() {
+ const [isHydrated, setIsHydrated] = useState(false)
+ useEffect(() => {
+ setIsHydrated(true)
+ }, [])
+
return (
Page with Links
@@ -62,6 +68,7 @@ export default function Page() {
+
{isHydrated ? 'hydrated' : 'hydrating'}
)
}
diff --git a/tests/fixtures/middleware-pages/pages/link/index.js b/tests/fixtures/middleware-pages/pages/link/index.js
index 73699d73a1..e0d58ba263 100644
--- a/tests/fixtures/middleware-pages/pages/link/index.js
+++ b/tests/fixtures/middleware-pages/pages/link/index.js
@@ -1,6 +1,12 @@
+import { useState, useEffect } from 'react'
import Link from 'next/link'
export default function Page() {
+ const [isHydrated, setIsHydrated] = useState(false)
+ useEffect(() => {
+ setIsHydrated(true)
+ }, [])
+
return (
Page with Links
@@ -62,6 +68,7 @@ export default function Page() {
+
{isHydrated ? 'hydrated' : 'hydrating'}
)
}
diff --git a/tests/fixtures/middleware/next.config.js b/tests/fixtures/middleware/next.config.js
index 03c2828b32..54308b902a 100644
--- a/tests/fixtures/middleware/next.config.js
+++ b/tests/fixtures/middleware/next.config.js
@@ -19,6 +19,11 @@ const nextConfig = {
return config
},
+ // turbopack becomes default for builds in Next 16. There is failure when webpack configuration is present
+ // without turbopack configuration, so we add a turbopack configuration here to ensure this fixture
+ // works with default build bundler for all tested versions
+ // see https://github.com/vercel/next.js/blob/ba5a0ca79944b4c8a59d80d677bfedaf0fef33d6/packages/next/src/lib/turbopack-warning.ts#L159-L177
+ turbopack: {},
outputFileTracingRoot: __dirname,
}
diff --git a/tests/fixtures/nx-integrated/.gitignore b/tests/fixtures/nx-integrated/.gitignore
index f44f4e80ba..ffa6719d96 100644
--- a/tests/fixtures/nx-integrated/.gitignore
+++ b/tests/fixtures/nx-integrated/.gitignore
@@ -39,9 +39,12 @@ testem.log
Thumbs.db
.nx/cache
+.nx/workspace-data
# Next.js
.next
# Local Netlify folder
.netlify
+.cursor/rules/nx-rules.mdc
+.github/instructions/nx.instructions.md
diff --git a/tests/fixtures/nx-integrated/nx.json b/tests/fixtures/nx-integrated/nx.json
index 706a7a57a8..6e5eda2808 100644
--- a/tests/fixtures/nx-integrated/nx.json
+++ b/tests/fixtures/nx-integrated/nx.json
@@ -31,5 +31,6 @@
"linter": "eslint"
}
}
- }
+ },
+ "useInferencePlugins": false
}
diff --git a/tests/fixtures/nx-integrated/package.json b/tests/fixtures/nx-integrated/package.json
index 814f4d924b..8635fc4801 100644
--- a/tests/fixtures/nx-integrated/package.json
+++ b/tests/fixtures/nx-integrated/package.json
@@ -13,18 +13,17 @@
"tslib": "^2.3.0"
},
"devDependencies": {
- "@nx/js": "17.3.0",
- "@nx/next": "17.3.0",
- "@nx/workspace": "17.3.0",
- "@swc-node/register": "~1.6.7",
- "@swc/core": "~1.3.85",
- "@swc/helpers": "~0.5.2",
+ "@nx/js": "21.6.3",
+ "@nx/next": "21.6.3",
+ "@nx/workspace": "21.6.3",
+ "@swc-node/register": "1.9.2",
+ "@swc/core": "1.5.7",
+ "@swc/helpers": "0.5.17",
"@types/node": "18.16.9",
"@types/react": "18.2.33",
"@types/react-dom": "18.2.14",
- "nx": "17.3.0",
+ "nx": "21.6.3",
"ts-node": "10.9.1",
"typescript": "~5.3.2"
- },
- "packageManager": "pnpm@8.9.0"
+ }
}
diff --git a/tests/fixtures/page-router-404-get-static-props-with-revalidate/pages/404.js b/tests/fixtures/page-router-404-get-static-props-with-revalidate/pages/404.js
index cb047699af..d44d5f5d5b 100644
--- a/tests/fixtures/page-router-404-get-static-props-with-revalidate/pages/404.js
+++ b/tests/fixtures/page-router-404-get-static-props-with-revalidate/pages/404.js
@@ -1,6 +1,6 @@
export default function NotFound({ timestamp }) {
return (
-
+
Custom 404 page with revalidate:
{timestamp}
)
diff --git a/tests/fixtures/page-router-base-path-i18n/pages/404.js b/tests/fixtures/page-router-base-path-i18n/pages/404.js
index 0f42ed27ed..75e2ba1607 100644
--- a/tests/fixtures/page-router-base-path-i18n/pages/404.js
+++ b/tests/fixtures/page-router-base-path-i18n/pages/404.js
@@ -1,6 +1,6 @@
export default function NotFound({ locale }) {
return (
-
+
Custom 404 page for locale:
{locale}
)
diff --git a/tests/fixtures/page-router/pages/404.js b/tests/fixtures/page-router/pages/404.js
index 3c251e6665..a1c17694d1 100644
--- a/tests/fixtures/page-router/pages/404.js
+++ b/tests/fixtures/page-router/pages/404.js
@@ -1,3 +1,3 @@
export default function NotFound() {
- return Custom 404 page
+ return Custom 404 page
}
diff --git a/tests/fixtures/wasm-src/next.config.js b/tests/fixtures/wasm-src/next.config.js
index 4263b7f9c2..07ebbcc865 100644
--- a/tests/fixtures/wasm-src/next.config.js
+++ b/tests/fixtures/wasm-src/next.config.js
@@ -1,5 +1,6 @@
const { platform } = require('process')
const fsPromises = require('fs/promises')
+const { satisfies } = require('semver')
// Next.js uses `fs.promises.copyFile` to copy files from `.next`to the `.next/standalone` directory
// It tries copying the same file twice in parallel. Unix is fine with that, but Windows fails
@@ -28,4 +29,27 @@ module.exports = {
ignoreDuringBuilds: true,
},
outputFileTracingRoot: __dirname,
+ // there is no single way to use `next/og` or `@vercel/og` depending on Next.js version
+ // - next@<14 doesn't have 'next/og' export
+ // - next turbopack builds doesn't work with `@vercel/og`
+ // so this adds `next-og-alias` alias depending on next version for both webpack and turbopack
+ // so we can test this in all the versions
+ webpack: (config) => {
+ const hasNextOg = !satisfies(require('next/package.json').version, '<14.0.0', {
+ includePrerelease: true,
+ })
+
+ if (!hasNextOg) {
+ config.resolve.alias['next-og-alias$'] = '@vercel/og'
+ } else {
+ config.resolve.alias['next-og-alias$'] = 'next/og'
+ }
+
+ return config
+ },
+ turbopack: {
+ resolveAlias: {
+ 'next-og-alias': 'next/og',
+ },
+ },
}
diff --git a/tests/fixtures/wasm-src/package.json b/tests/fixtures/wasm-src/package.json
index d5a533479f..7cbbd4d7ba 100644
--- a/tests/fixtures/wasm-src/package.json
+++ b/tests/fixtures/wasm-src/package.json
@@ -11,6 +11,7 @@
"@vercel/og": "latest",
"next": "latest",
"react": "18.2.0",
- "react-dom": "18.2.0"
+ "react-dom": "18.2.0",
+ "semver": "^7.7.2"
}
}
diff --git a/tests/fixtures/wasm-src/src/app/og-node/route.js b/tests/fixtures/wasm-src/src/app/og-node/route.js
index 6338e7e61b..2fa26189c2 100644
--- a/tests/fixtures/wasm-src/src/app/og-node/route.js
+++ b/tests/fixtures/wasm-src/src/app/og-node/route.js
@@ -1,4 +1,5 @@
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export async function GET() {
return new ImageResponse(hi
, {
diff --git a/tests/fixtures/wasm-src/src/app/og/route.js b/tests/fixtures/wasm-src/src/app/og/route.js
index 575c5a01ae..ba3552647f 100644
--- a/tests/fixtures/wasm-src/src/app/og/route.js
+++ b/tests/fixtures/wasm-src/src/app/og/route.js
@@ -1,4 +1,5 @@
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export async function GET() {
return new ImageResponse(hi
, {
diff --git a/tests/fixtures/wasm-src/src/pages/api/og-wrong-runtime.js b/tests/fixtures/wasm-src/src/pages/api/og-wrong-runtime.js
index a693c6f5df..58ed5d86c5 100644
--- a/tests/fixtures/wasm-src/src/pages/api/og-wrong-runtime.js
+++ b/tests/fixtures/wasm-src/src/pages/api/og-wrong-runtime.js
@@ -1,5 +1,5 @@
-// /pages/api/og.jsx
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export default function () {
return new ImageResponse(
diff --git a/tests/fixtures/wasm-src/src/pages/api/og.js b/tests/fixtures/wasm-src/src/pages/api/og.js
index 55ab54d2c1..f3885a194e 100644
--- a/tests/fixtures/wasm-src/src/pages/api/og.js
+++ b/tests/fixtures/wasm-src/src/pages/api/og.js
@@ -1,5 +1,5 @@
-// /pages/api/og.jsx
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export const config = {
runtime: 'edge',
diff --git a/tests/fixtures/wasm/app/og-node/route.js b/tests/fixtures/wasm/app/og-node/route.js
index 6338e7e61b..2fa26189c2 100644
--- a/tests/fixtures/wasm/app/og-node/route.js
+++ b/tests/fixtures/wasm/app/og-node/route.js
@@ -1,4 +1,5 @@
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export async function GET() {
return new ImageResponse(hi
, {
diff --git a/tests/fixtures/wasm/app/og/route.js b/tests/fixtures/wasm/app/og/route.js
index 575c5a01ae..ba3552647f 100644
--- a/tests/fixtures/wasm/app/og/route.js
+++ b/tests/fixtures/wasm/app/og/route.js
@@ -1,4 +1,5 @@
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export async function GET() {
return new ImageResponse(hi
, {
diff --git a/tests/fixtures/wasm/next.config.js b/tests/fixtures/wasm/next.config.js
index 4263b7f9c2..8f60441cf4 100644
--- a/tests/fixtures/wasm/next.config.js
+++ b/tests/fixtures/wasm/next.config.js
@@ -1,5 +1,6 @@
const { platform } = require('process')
const fsPromises = require('fs/promises')
+const { satisfies } = require('semver')
// Next.js uses `fs.promises.copyFile` to copy files from `.next`to the `.next/standalone` directory
// It tries copying the same file twice in parallel. Unix is fine with that, but Windows fails
@@ -28,4 +29,28 @@ module.exports = {
ignoreDuringBuilds: true,
},
outputFileTracingRoot: __dirname,
+ outputFileTracingRoot: __dirname,
+ // there is no single way to use `next/og` or `@vercel/og` depending on Next.js version
+ // - next@<14 doesn't have 'next/og' export
+ // - next turbopack builds doesn't work with `@vercel/og`
+ // so this adds `next-og-alias` alias depending on next version for both webpack and turbopack
+ // so we can test this in all the versions
+ webpack: (config) => {
+ const hasNextOg = !satisfies(require('next/package.json').version, '<14.0.0', {
+ includePrerelease: true,
+ })
+
+ if (!hasNextOg) {
+ config.resolve.alias['next-og-alias$'] = '@vercel/og'
+ } else {
+ config.resolve.alias['next-og-alias$'] = 'next/og'
+ }
+
+ return config
+ },
+ turbopack: {
+ resolveAlias: {
+ 'next-og-alias': 'next/og',
+ },
+ },
}
diff --git a/tests/fixtures/wasm/package.json b/tests/fixtures/wasm/package.json
index d5a533479f..7cbbd4d7ba 100644
--- a/tests/fixtures/wasm/package.json
+++ b/tests/fixtures/wasm/package.json
@@ -11,6 +11,7 @@
"@vercel/og": "latest",
"next": "latest",
"react": "18.2.0",
- "react-dom": "18.2.0"
+ "react-dom": "18.2.0",
+ "semver": "^7.7.2"
}
}
diff --git a/tests/fixtures/wasm/pages/api/og-wrong-runtime.js b/tests/fixtures/wasm/pages/api/og-wrong-runtime.js
index a693c6f5df..58ed5d86c5 100644
--- a/tests/fixtures/wasm/pages/api/og-wrong-runtime.js
+++ b/tests/fixtures/wasm/pages/api/og-wrong-runtime.js
@@ -1,5 +1,5 @@
-// /pages/api/og.jsx
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export default function () {
return new ImageResponse(
diff --git a/tests/fixtures/wasm/pages/api/og.js b/tests/fixtures/wasm/pages/api/og.js
index 55ab54d2c1..f3885a194e 100644
--- a/tests/fixtures/wasm/pages/api/og.js
+++ b/tests/fixtures/wasm/pages/api/og.js
@@ -1,5 +1,5 @@
-// /pages/api/og.jsx
-import { ImageResponse } from '@vercel/og'
+// see next.config for details about 'next-og-alias'
+import { ImageResponse } from 'next-og-alias'
export const config = {
runtime: 'edge',
diff --git a/tests/integration/simple-app.test.ts b/tests/integration/simple-app.test.ts
index d49dcc9e3d..7d865559fc 100644
--- a/tests/integration/simple-app.test.ts
+++ b/tests/integration/simple-app.test.ts
@@ -35,6 +35,7 @@ import {
startMockBlobStore,
} from '../utils/helpers.js'
import {
+ hasDefaultTurbopackBuilds,
nextVersionSatisfies,
shouldHaveAppRouterGlobalErrorInPrerenderManifest,
shouldHaveAppRouterNotFoundInPrerenderManifest,
@@ -421,19 +422,23 @@ test.skipIf(process.env.NEXT_VERSION !== 'canary')(
},
)
-test('can require CJS module that is not bundled', async (ctx) => {
- await createFixture('simple', ctx)
- await runPlugin(ctx)
+// setup for this test only works with webpack builds due to usage of ` __non_webpack_require__` to avoid bundling a file
+test.skipIf(hasDefaultTurbopackBuilds())(
+ 'can require CJS module that is not bundled',
+ async (ctx) => {
+ await createFixture('simple', ctx)
+ await runPlugin(ctx)
- const response = await invokeFunction(ctx, { url: '/api/cjs-file-with-js-extension' })
+ const response = await invokeFunction(ctx, { url: '/api/cjs-file-with-js-extension' })
- expect(response.statusCode).toBe(200)
+ expect(response.statusCode).toBe(200)
- const parsedBody = JSON.parse(response.body)
+ const parsedBody = JSON.parse(response.body)
- expect(parsedBody.notBundledCJSModule.isBundled).toEqual(false)
- expect(parsedBody.bundledCJSModule.isBundled).toEqual(true)
-})
+ expect(parsedBody.notBundledCJSModule.isBundled).toEqual(false)
+ expect(parsedBody.bundledCJSModule.isBundled).toEqual(true)
+ },
+)
describe('next patching', async () => {
const { cp: originalCp, appendFile } = (await vi.importActual(
diff --git a/tests/utils/create-e2e-fixture.ts b/tests/utils/create-e2e-fixture.ts
index fe2546da2e..639a996aeb 100644
--- a/tests/utils/create-e2e-fixture.ts
+++ b/tests/utils/create-e2e-fixture.ts
@@ -69,7 +69,10 @@ export const createE2EFixture = async (fixture: string, config: E2EConfig = {})
}
console.log('\n\n\n🪵 Deploy logs:')
console.log(logs)
- // on failures we don't delete the deploy
+ // on failures we don't delete the deploy, but we do cleanup the fixture from filesystem in CI
+ if (process.env.CI) {
+ return cleanup(isolatedFixtureRoot, undefined)
+ }
}
try {
const [packageName] = await Promise.all([
@@ -392,14 +395,12 @@ export const fixtureFactories = {
serverComponents: () => createE2EFixture('server-components'),
nxIntegrated: () =>
createE2EFixture('nx-integrated', {
- packageManger: 'pnpm',
packagePath: 'apps/next-app',
buildCommand: 'nx run next-app:build',
publishDirectory: 'dist/apps/next-app/.next',
}),
nxIntegratedDistDir: () =>
createE2EFixture('nx-integrated', {
- packageManger: 'pnpm',
packagePath: 'apps/custom-dist-dir',
buildCommand: 'nx run custom-dist-dir:build',
publishDirectory: 'dist/apps/custom-dist-dir/dist',
diff --git a/tests/utils/fixture.ts b/tests/utils/fixture.ts
index d0f92bf530..8dfc6b83d7 100644
--- a/tests/utils/fixture.ts
+++ b/tests/utils/fixture.ts
@@ -31,7 +31,7 @@ import {
} from '../../src/build/plugin-context.js'
import { BLOB_TOKEN } from './constants.mjs'
import { type FixtureTestContext } from './contexts.js'
-import { setNextVersionInFixture } from './next-version-helpers.mjs'
+import { hasDefaultTurbopackBuilds, setNextVersionInFixture } from './next-version-helpers.mjs'
const bootstrapURL = await getBootstrapURL()
const actualCwd = await vi.importActual('process').then((p) => p.cwd())
@@ -569,5 +569,8 @@ export async function invokeSandboxedFunction(
}
export const EDGE_MIDDLEWARE_FUNCTION_NAME = '___netlify-edge-handler-middleware'
-export const EDGE_MIDDLEWARE_SRC_FUNCTION_NAME = '___netlify-edge-handler-src-middleware'
+// Turbopack has different output than webpack
+export const EDGE_MIDDLEWARE_SRC_FUNCTION_NAME = hasDefaultTurbopackBuilds()
+ ? EDGE_MIDDLEWARE_FUNCTION_NAME
+ : '___netlify-edge-handler-src-middleware'
export const NODE_MIDDLEWARE_FUNCTION_NAME = '___netlify-edge-handler-node-middleware'
diff --git a/tests/utils/next-version-helpers.mjs b/tests/utils/next-version-helpers.mjs
index 018639ab49..5761f20ca6 100644
--- a/tests/utils/next-version-helpers.mjs
+++ b/tests/utils/next-version-helpers.mjs
@@ -49,6 +49,10 @@ export function hasNodeMiddlewareSupport() {
return nextVersionSatisfies(isNextCanary() ? '>=15.2.0' : '>=15.5.0')
}
+export function hasDefaultTurbopackBuilds() {
+ return nextVersionSatisfies('>=15.6.0-canary.40')
+}
+
/**
* Check if current next version requires React 19
* @param {string} version Next version