Next.js 测试体系详解:从 pnpm test 命令、隔离测试沙箱到 Turbopack 与部署测试 📅 发布时间:2026/9/7 18:40:06 👁 浏览次数: Next.js 测试体系详解从 pnpm test 命令、隔离测试沙箱到 Turbopack 与部署测试【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.jsNext.js 仓库维护着 React 框架最庞大的测试矩阵e2e、development、production 三类隔离测试分别针对next dev、next start和 Vercel 部署环境运行所有测试都通过nextTestSetup在系统临时目录中构建一个与 monorepo 完全隔离的 Next.js 实例。读完本文你将掌握如何按目录模式运行指定测试套件、用pnpm new-test脚手架创建新测试、利用NEXT_TEST_SKIP_CLEANUP等环境变量排查隔离测试失败、用 Playwright trace 与 Chrome DevTools 调试测试过程以及如何在仓库外部用pnpm pack-next本地构建产物做集成验证。运行测试前的准备运行任何测试之前必须先构建整个项目生成packages/next/dist下的产物pnpm build官方推荐使用“目录模式”的方式运行测试即把测试目录作为参数传给脚本。以test/e2e/app-dir/app套件为例# production 模式next build next start pnpm test-start test/e2e/app-dir/app/ # development 模式next dev pnpm test-dev test/e2e/app-dir/app/这些脚本的底层实现是 scripts/run-jest.sh它把--modedev|start|deploy翻译成NEXT_TEST_MODE环境变量把--bundlerwebpack|turbo|rspack翻译成IS_WEBPACK_TEST/IS_TURBOPACK_TEST/NEXT_RSPACK等变量随后exec jest --runInBand执行测试。从 package.json 的 scripts 定义可以看到完整的别名矩阵test-dev/test-start/test-deployheadless 模式浏览器在后台运行看不到窗口testonly-dev/testonly-start/testonly-deploy去掉--headless测试运行时会弹出浏览器窗口方便调试某个具体用例test-dev-turbo、test-start-turbo、test-deploy-turbo用 Turbopack 作为打包器运行测试test-dev-rspack、test-start-rspack等rspack 对应版本test不带 mode 的通用入口默认--bundlerwebpack --headless。调试单个测试时把pnpm test-start换成pnpm testonly-start即可看到浏览器窗口pnpm testonly-start test/e2e/app-dir/app/隔离测试沙箱nextTestSetup 的工作原理e2e、development 和 production 测试都在与仓库完全隔离的环境中运行当你执行test/e2e、test/production或test/development下的测试时会在系统临时目录如/tmp中创建一个 Next.js 的本地版本并链接到一个隔离的应用副本随后在随机端口上启动一个服务器供测试访问全部测试结束后服务器被销毁、临时目录中的残留文件也被删除。整套逻辑由nextTestSetup自动处理。其实现位于 test/lib/e2e-utils/index.tsnextTestSetup接收createNext的选项外加skipDeployment、dir返回测试所需的上下文对象export function nextTestSetup( options: Parameterstypeof createNext[0] { skipDeployment?: boolean dir?: string } ): { isNextDev: boolean isNextDeploy: boolean isNextStart: boolean isTurbopack: boolean isRspack: boolean next: NextInstance skipped: boolean }从源码结构看有几个值得了解的细节模式判定模块加载时根据测试文件所在目录e2e/development/production与NEXT_TEST_MODE环境变量确定当前实例类型e2e 目录下合法的 mode 为dev、start、deploy未设置NEXT_TEST_MODE时默认回退为start并打印警告见 test/lib/e2e-utils/index.ts#L97-L119超时策略单个测试用例被强制包裹 60 秒超时individualTestTimeout而 setup 阶段首次createNext/ 启动默认给 120 秒Windows 上放宽到 240 秒可用NEXT_E2E_TEST_TIMEOUT覆盖懒加载门控force-gatenextTestSetup在beforeAll钩子中延迟创建 Next 实例会先解析 fixture 的next.config若gate门控条件决定跳过则连构建都省掉直接让整个套件 force-pass避免不必要的 fixture 安装与构建开销实例创建失败即抛错createNext失败时不会直接退出进程而是销毁半成品实例后throw确保 Jest 能把相关测试标记为失败。编写新测试使用 pnpm new-test 脚手架创建新测试的推荐入口是pnpm new-test该脚本在 package.json 中定义为turbo gen test即调用 Turborepo 的 generator生成器配置见 turbo/generators/config.ts按测试类型从模板起步并自动使用nextTestSetup搭建隔离安装避免测试无意间依赖 monorepo 内部状态而写出“错误但通过”的用例。官方示例e2e / development / production 测试应使用nextTestSetup工具函数仓库中给出的示例在 test/e2e/example.txt其中{{name}}为模板占位符完整展示了四种断言方式import { nextTestSetup } from e2e-utils describe({{name}}, () { const { next } nextTestSetup({ files: __dirname, }) // 推荐检查 HTML 时使用 cheeriojQuery 风格的 API it(should work using cheerio, async () { const $ await next.render$(/) expect($(p).text()).toBe(hello world) }) // 推荐需要完整浏览器时使用 browser API it(should work using browser, async () { const browser await next.browser(/) expect(await browser.elementByCss(p).text()).toBe(hello world) }) // 需要完整 HTML 字符串时cheerio 中也可用 $.html() it(should work with html, async () { const html await next.render(/) expect(html).toContain(hello world) }) // 需要测试 Response 对象时 it(should work with fetch, async () { const res await next.fetch(/) const html await res.text() expect(html).toContain(hello world) }) })测试类型一览测试类型运行环境说明e2enext dev、next start及 Vercel 部署端到端测试位于test/e2edevelopmentnext dev针对开发模式位于test/developmentproductionnext start针对生产构建产物位于test/productionintegration各种杂项检查与模式历史遗留位置测试不隔离于 monorepo理想情况下不再往这里新增套件unit无浏览器、不启动 next极快的纯工具函数测试位于test/unit编写规范统一使用 TypeScript所有新测试套件都应写成.ts单元测试为.tsx以便在测试代码本身捕获类型层面的小问题减少 flaky 或错误测试的出现优先复用既有套件如果被测主题与已有套件高度相关例如 hash 导航与既有的导航测试套件应把新检查追加进现有套件而不是另起炉灶等待异步条件检查可能耗时生效的条件时必须显式等待——浏览器侧用waitForElement非浏览器侧用next-test-utils中的check工具验证修复有效性应用修复前先确认测试在修复前会失败这样才能保证测试真正能捕获回归。调试辅助环境变量以下测试专用环境变量通过前缀在pnpm test命令前传入NEXT_TEST_SKIP_CLEANUP1 pnpm test-start test/e2e/app-dir/app/环境变量作用NEXT_TEST_SKIP_CLEANUP1阻止删除测试创建的临时目录随后可进入该目录运行pnpm debug调试完整搭好的测试项目NEXT_SKIP_ISOLATE1跳过隔离安装测试直接在 Next.js 仓库内运行。可缩短本地测试耗时但不兼容所有测试NEXT_TEST_MODE为e2e目录切换测试模式适用于不直接通过pnpm test-dev/pnpm test-start运行的场景。合法取值见 test/lib/e2e-utils/index.ts#L46 及该文件 L112 处的validE2EModes [dev, start, deploy]NEXT_TEST_DEPLOY_URL配合pnpm test-deploy使用跳过 Vercel 部署步骤直接对已有部署 URL 执行 deploy 模式断言NEXT_TEST_PREFER_OFFLINE1测试搭建时为包管理器附加--prefer-offline参数适合飞机、公共 Wi-Fi 等网络受限环境NEXT_E2E_TEST_TIMEOUT覆盖 setup 阶段超时秒设为0常用于调试时挂起NEXT_TEST_TRACE1开启测试性能剖析profiling用于改进测试基础设施调试测试Playwright traceCI 失败排查测试在 CI 中失败时工作流会尝试抓取 Playwright 运行轨迹工作流完成后会上传test-trace产物下载、解压后可用以下命令检查pnpm playwright show-trace ./path/to/trace挂载 Chrome Debugger 到 Next 服务器最简单的方式是修改测试中的nextTestSetup调用向 next 进程透传--inspectconst { next } nextTestSetup({ ... startArgs: [--inspect], })同时建议设置NEXT_E2E_TEST_TIMEOUT0让服务器在调试期间不被超时终止。调试测试进程本身给运行 Jest 的 node 进程传inspect标志例如IS_TURBOPACK_TEST1 TURBOPACK_DEV1 NEXT_TEST_MODEdev node --inspect node_modules/jest/bin/jest.js ...使用 Turbopack 运行测试使用带-turbo后缀的 npm 脚本即可用 Turbopack 运行测试套件pnpm test-dev-turbo test/e2e/app-dir/app/如果想让同一个测试同时跑 Turbopack 和 Webpack用 Jest 的--projects标志同时加载两个 Jest 项目配置pnpm test-dev test/e2e/app-dir/app/ --projects jest.config.*这会同时匹配 jest.config.js 与 jest.config.turbopack.js从而在两种打包器下对比验证行为一致性。Deploy 测试Deploy 测试验证 Next.js 部署到 Vercel 后的正确性。它们属于 e2e 测试套件的一部分针对真实的 Vercel 部署运行。PR 上触发 Deploy 测试Deploy 测试在canary分支自动运行但默认不会在每个 PR 上触发PR 中新建或修改的测试文件会触发对应的 deploy 测试。也可以手动触发 deploy 测试工作流并指向你的分支需传入自定义 tarball。本地运行 Deploy 测试可用NEXT_TEST_VERSION环境变量针对特定 commit 在本地运行 deploy 测试NEXT_TEST_VERSIONhttps://vercel-packages.vercel.app/next/commits/commitSha/next pnpm test-deploy path-to-test例如针对 commitabc123NEXT_TEST_VERSIONhttps://vercel-packages.vercel.app/next/commits/abc123/next pnpm test-deploy test/e2e/app-dir/actions/该命令会从指定 commit 下载预构建的 Next.js tarball并对它运行 deploy 测试。如果已有部署 URL 想跳过 Vercel 部署步骤改用NEXT_TEST_DEPLOY_URLNEXT_TEST_DEPLOY_URLhttps://your-deployment.vercel.app pnpm test-deploy test/e2e/app-dir/actions/仓库外集成测试本地构建在仓库外部用本地构建做集成验证时可以先为仓库中的每个包生成本地构建pnpm pack-next该脚本的实现在 scripts/pack-next.ts。指定项目目录后可自动改写项目的package.jsonpnpm pack-next --project ~/shadcn-ui/apps/www/必要时会自动发现并修改父级 workspace。这类自动改写对npm与pnpm有效已知与bun、yarn不兼容。通过参数分隔符--可以向napiCLI 追加参数例如pnpm pack-next --project ~/my-project/ -- --release更多选项可用pnpm pack-next --help查看。本地创建 tarballpnpm pack-next --tartarball 会写入仓库根目录的tarballs目录并打印如何通过修改 workspacepackage.json来使用这些 tarball 的说明。在 Linux 上为避免超过 2 GiB已知会导致pnpm出现问题会生成 stripped 的next/swc二进制可用--compress objcopy-zstd覆盖该行为速度更慢但保留 debuginfo。要创建可随项目部署的 tarballpnpm pack-next --project ~/my-project/ --deployable-tartarball 会写到被修补项目package.json旁边的tarballs目录并使用相对file:引用从而可以被项目直接包含。也可以绕过包管理器、把 tarball 直接解包到项目的node_modules实现在 scripts/unpack-next.tspnpm unpack-next ~/shadcn-ui不过这不推荐作为常规做法——用包管理器安装更安全。仓库外集成测试Preview 构建每个分支构建都会为仓库中的每个包生成 tarball并非所有原生包都会自动构建build-and-deploy会跳过next-swc中耗时且很少使用的原生变体要强制构建全部包可手动触发build-and-deploy工作流的workflow_dispatch这些产物可直接用于外部仓库。用法是把package.json中的版本号替换为https://vercel-packages.vercel.app的 URL。依赖会自动改写为与所用包相同的 commit SHA——例如从 commitabc安装next时它依赖的next/env与使用的next-swc也都会指向 commitabc。使用指定 commit 的next必须提供完整 SHA{ dependencies: { next: https://vercel-packages.vercel.app/next/commits/188f76947389a27e9bcff8ebf9079433679256a7/next } }或使用指定 PR 的next需要 PR 编号{ dependencies: { next: https://vercel-packages.vercel.app/next/prs/66445/next } }小结Next.js 的测试体系围绕三个设计支柱展开其一所有 e2e / development / production 测试都经由nextTestSetuptest/lib/e2e-utils/index.ts在临时目录中构建隔离的 Next.js 安装保证测试不会意外依赖 monorepo 内部状态其二scripts/run-jest.sh把 modedev / start / deploy与 bundlerwebpack / turbo / rspack两个维度正交组合成完整的脚本别名矩阵testonly-*与--projects分别服务于可视化调试和多打包器对比其三围绕NEXT_TEST_SKIP_CLEANUP、NEXT_SKIP_ISOLATE、NEXT_TEST_TRACE、NEXT_TEST_VERSION、NEXT_TEST_DEPLOY_URL等环境变量的调试与剖析手段覆盖了从本地临时目录排查到真实 Vercel 部署验证的完整链路。新贡献者只要遵循pnpm new-test脚手架 TypeScript nextTestSetup的规范即可按本文路径为 Next.js 编写可复现、可调试、能捕获回归的测试。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考