mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
357b2b3c4c
### What? Migrate the five local isolated test installs that explicitly used npm to pnpm. The Nx fixture now has pnpm workspace metadata, while filesystem-layout-sensitive fixtures use pnpm's hoisted linker with copied package files. ### Why? The npm-based Nx install bypassed the repository's centralized supply-chain protections and could select a package immediately after publication, including temporarily incomplete multi-package releases. Using pnpm makes isolated installs inherit the repository's `minimumReleaseAge`, exclusions, and exotic-subdependency policy. The other npm installs depended on npm-style real package directories. On Node versions affected by nodejs/node#65113, hoisted/copy mode preserves that layout without leaving these fixtures outside the shared pnpm security configuration; fixed Node releases use normal pnpm linking. ### How? - Use normal pnpm workspace resolution for the Nx fixture. - Use `node-linker=hoisted` and `package-import-method=copy` for filesystem tests only on affected Node releases; Node 24.21+ and 26.8+ use normal linking. Node 20 CI keeps the workaround because no fixed Node 20 release exists. - Validate local `@next/env` tarballs through the lockfile when hoisted installs do not expose pnpm's virtual-store path marker. - Keep the deployment-environment npm install unchanged. ### Verification - `pnpm build-all` - `pnpm types` - A 9-version throwaway assertion verified the affected/fixed Node release matrix - `pnpm test-dev-turbo test/e2e/app-dir/nx-handling/nx-handling.test.ts test/e2e/handle-non-hoisted-swc-helpers/index.test.ts test/e2e/filesystem-cache/filesystem-cache.test.ts test/e2e/filesystem-cache/warm-restart-task-stats.test.ts test/e2e/filesystem-cache/evict-after-snapshot.test.ts` — all 25 tests passed after installing the sandbox's missing Playwright browser - Production Turbopack: Nx, non-hoisted SWC helper, build-cache-default, and warm restart passed (9/9) - `filesystem-cache.test.ts` production baseline: 15/17 passed; the same two cache-growth bounds fail under both the unchanged npm fixture and the pnpm fixture at nearly identical percentages, so they are pre-existing sandbox-specific failures - Generated-layout inspection: no package symlinks outside expected `.bin` command shims; package files are copied; `node_modules/.pnpm` is metadata-only <!-- NEXT_JS_LLM --> <!-- fleet 81cd457d-6956-4cf9-b6f6-9ebf9d95f285 --> --------- Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
import { getPnpmRealpathWorkaround } from '../../lib/pnpm-realpath-workaround'
|
|
import { retry, waitFor } from 'next-test-utils'
|
|
|
|
// Eviction requires the dev server (HMR) and persistent caching (Turbopack).
|
|
// Skip entirely in prod/start mode.
|
|
// TODO(deploy-test-completion): Re-enable this suite in deploy mode.
|
|
// It likely mutates files in the isolated local fixture after setup.
|
|
// @force-gate !deploy
|
|
// @force-gate dev
|
|
describe('evict-after-snapshot', () => {
|
|
const env = {
|
|
ENABLE_CACHING: '1',
|
|
TURBO_ENGINE_IGNORE_DIRTY: '1',
|
|
TURBO_ENGINE_SNAPSHOT_IDLE_TIMEOUT_MILLIS: '1000',
|
|
// Persist even tiny snapshots so the test doesn't depend on the
|
|
// minimum-compilation-time threshold.
|
|
TURBO_ENGINE_SNAPSHOT_MIN_ACTIVE_TIME_MILLIS: '0',
|
|
ENABLE_EVICTION: '1',
|
|
}
|
|
|
|
const { next } = nextTestSetup({
|
|
files: __dirname,
|
|
overrideFiles: getPnpmRealpathWorkaround(),
|
|
env,
|
|
})
|
|
|
|
async function waitForSnapshotAndEviction() {
|
|
// The idle timeout is 1s, give extra time for snapshot + eviction to complete
|
|
await waitFor(5000)
|
|
}
|
|
|
|
// Turbopack-only: eviction requires persistent caching
|
|
;(process.env.IS_TURBOPACK_TEST ? it : it.skip)(
|
|
'should serve correct content after eviction and HMR',
|
|
async () => {
|
|
const browser = await next.browser('/')
|
|
await retry(async () => {
|
|
expect(await browser.elementByCss('p').text()).toBe('hello world')
|
|
})
|
|
|
|
let currentContent = 'hello world'
|
|
for (let cycle = 1; cycle <= 3; cycle++) {
|
|
await waitForSnapshotAndEviction()
|
|
|
|
const prevContent = currentContent
|
|
const nextContent = `cycle ${cycle}`
|
|
await next.patchFile('app/page.tsx', (content) =>
|
|
content.replace(prevContent, nextContent)
|
|
)
|
|
currentContent = nextContent
|
|
|
|
const expected = currentContent
|
|
await retry(async () => {
|
|
expect(await browser.elementByCss('p').text()).toBe(expected)
|
|
}, 10000)
|
|
}
|
|
|
|
await browser.close()
|
|
},
|
|
90000
|
|
)
|
|
;(process.env.IS_TURBOPACK_TEST ? it : it.skip)(
|
|
'should handle client component HMR after eviction',
|
|
async () => {
|
|
const browser = await next.browser('/client')
|
|
await retry(async () => {
|
|
expect(await browser.elementByCss('p').text()).toBe('hello world')
|
|
})
|
|
|
|
await waitForSnapshotAndEviction()
|
|
|
|
await next.patchFile(
|
|
'app/client/page.tsx',
|
|
(content) => content.replace('hello world', 'hello eviction'),
|
|
async () => {
|
|
await retry(async () => {
|
|
expect(await browser.elementByCss('p').text()).toBe(
|
|
'hello eviction'
|
|
)
|
|
}, 10000)
|
|
}
|
|
)
|
|
|
|
await browser.close()
|
|
},
|
|
90000
|
|
)
|
|
})
|