DEBUG.WIKI
雨云;给项目一台云服务器
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关

p-queue 10 在 jsdom 构造时报 eventTargets 类型错误

Jest 的 jsdom 环境混用 Node process 与 DOM EventTarget,可能让 p-queue 10 在构造时失败。按测试用途选择运行环境,避免伪造内部类型标记。

测试还没调用任何队列任务,new PQueue() 就抛出下面的错误:

TypeError: The "eventTargets" argument must be an instance of EventEmitter or EventTarget. Received an instance of PQueue

若它只发生在 Jest 的 jsdom 环境,先检查 p-queue 是否升级到了 10.0.0。该版改用 EventTarget,构造器还会从 Node 的 process 取得 node:events,调用 setMaxListeners(Infinity, this)。jsdom 中的 EventTarget 与 Node 接受的那一类对象并不相同。

为什么浏览器和普通 Node 都正常

Jest 的 jsdom 环境有 DOM 全局对象,也保留了 process。于是队列继承的是 jsdom EventTarget,设置监听器上限用的却是 Node 实现。错误发生在这个交界处,不表示任务函数返回了错误类型,也不表示服务器连接超时。

已知组合包括 p-queue 10.0.0、Jest 与 jest-environment-jsdom 30.5、Node 24.19。相同错误也有 Vitest 环境反馈,但不能据此断言每一种 Vitest 配置都受影响。

纯队列测试可以使用 Node 环境

如果文件只测试并发、暂停和任务结果,没有读取 document、渲染组件或派发 DOM 事件,可以将该文件切换为 Node 环境:

/** @jest-environment node */
import PQueue from 'p-queue';

test('队列执行任务', async () => {
  const queue = new PQueue({ concurrency: 1 });
  const value = await queue.add(async () => 42);
  expect(value).toBe(42);
});

文件级声明放在顶部。项目如果通过自定义环境或其他配置覆盖它,应确认实际生效的环境。只把注释加到被测试模块里,不会改变测试文件的运行环境。

组件集成测试不能机械套用这段设置:切换后 document 不再存在。可将纯队列逻辑拆成独立测试,DOM 测试保留原环境;两者仍要覆盖组件调用队列的连接点。拆开测试不是证明原来的混合环境已经兼容。

不要给 DOM 类型冒充 Node 身份

给 EventTarget 添加 Symbol.for('nodejs.event_target') 能影响 Node 的内部识别,但这不是稳定的公开兼容接口。全局改动会作用于同一环境的其他库,不宜作为应用的常规修复。把 process 清空或屏蔽其 getBuiltinModule,同样可能破坏不相关模块。

正式 p-queue 10.0.0 的构造器仍直接调用 setMaxListeners;尚不能把讨论中的 try/catch 补丁当成已发布修复。确实必须在 jsdom 运行这一实现时,应等待或采用经过项目审查、范围明确的依赖补丁,保留补丁版本和撤回方式。

回归检查应从原来失败的测试入口执行,确认构造成功、任务结果正常、取消与错误处理仍可用。若采用 Node 环境,再确认被移动的文件没有丢失必须依赖 DOM 的断言;仅让空构造测试变绿还不够。