本地运行Jest测试正常,Jenkins中仅加--runInBand可运行,如何调试?
Jest 并行执行在Jenkins卡住问题排查
可能的诱因
- 并行Worker资源超限:Jest默认启动的Worker数量为CPU核心数减1,很多Jenkins构建节点为容器化部署,容器能看到宿主机的全部CPU核心,但实际被限制了可用CPU配额,导致大量Worker争抢有限的CPU资源引发死锁。本地环境CPU资源充足所以不会触发该问题。
- ts-jest多进程编译冲突:ts-jest默认会在编译时执行全量类型检查,多Worker并行运行时,多个进程同时读写类型检查缓存、
tsbuildinfo文件会触发资源锁,导致进程挂起。 - 测试用例资源竞争:测试用例如果存在共享全局资源的逻辑(比如同时读写同一个临时文件、连接同一个内存数据库实例、复用全局WebSocket连接等),本地运行速度快大概率不会触发竞争,Jenkins环境运行速度慢更容易触发资源竞争导致死锁。
- 环境依赖与权限差异:本地与Jenkins的Node.js、Jest、ts-jest、TypeScript版本不一致,部分旧版本存在多进程已知Bug;或是Jenkins执行用户对Jest缓存目录、项目构建目录没有读写权限,多进程同时尝试写文件时卡住。
最佳调试方案
第一步:定位触发问题的根因
- 本地模拟低资源并行场景,执行命令
jest --maxWorkers=2,如果本地也能复现卡住问题,说明是测试逻辑或ts-jest配置问题,和Jenkins环境无关。 - 给Jenkins的Jest执行命令增加调试参数:
jest --verbose --detectOpenHandles,执行后查看卡住前最后输出的测试用例名称,优先排查对应测试的资源占用逻辑,--detectOpenHandles会输出未正常关闭的IO句柄、定时器等资源。 - 验证是否为缓存问题:执行
jest --no-cache测试并行是否能正常运行,排除缓存读写冲突的可能性。
第二步:适配ts-jest配置
修改jest.config.js,开启ts-jest的独立编译模式,跳过全局类型检查(类型检查可单独执行tsc --noEmit实现),避免多进程类型检查冲突:
// 修改后的jest.config.js /* @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ module.exports = { roots: ["./src"], preset: "ts-jest", testEnvironment: "node", transform: { "^.+\\.(ts|tsx)?$": ["ts-jest", { isolatedModules: true }], }, testMatch: ["**/?(*.)+(spec|test).+(ts|tsx|js)"], }
第三步:适配Jenkins环境配置
- 固定Jenkins环境的Jest Worker数量,执行命令改为
jest --maxWorkers=2或jest --maxWorkers=50%,避免Worker数量超过实际可用CPU配额。 - 统一本地与Jenkins的依赖版本,提交
package-lock.json或yarn.lock到仓库,确保两端Node.js、Jest、ts-jest、TypeScript版本完全一致。 - 检查Jenkins构建目录的权限,确保执行用户对项目目录、Jest默认缓存目录(
~/.jest)有读写权限。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

