You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jest中等候NestJS事件监听函数执行完成?

问题

我使用NestJS结合Event Emitter开发功能,当向/profile接口发起PUT请求时,系统会触发profile.update事件。随后有一个监听函数响应该事件,调用外部服务完成资料更新后结束。

我的端到端(e2e)测试流程是向/profile发起PUT请求,之后检查外部服务是否完成了资料更新,但如果监听函数还未执行完成就进行检查,结果必然不准确。

如何等待该监听函数执行完毕后再检查外部服务状态?

我目前的尝试代码如下:

it("should be able to notify external service about profile update", async () => {
  const instance = app.get(NotifyExternalServiceAboutProfile);

  const spy = jest.spyOn(instance, 'handle');

  const { body } = await request(app.getHttpServer())
    .post('/profile')
    .send({
      name: 'John Doe'
    })
    .expect(201);

  await request(app.getHttpServer())
    .put('/profile/' + body.id)
    .send({
      name: 'Fulano de tal',
    })
    .expect(200);

  // How can I know if "NotifyExternalServiceAboutProfile" completed? Like a callback.
});
解决方案

方法1:用Jest的waitFor等待监听函数执行完成

Jest的waitFor可以轮询指定条件,直到条件满足或超时。我们可以通过监听handle方法的调用及执行状态来判断是否完成。

it("should be able to notify external service about profile update", async () => {
  const instance = app.get(NotifyExternalServiceAboutProfile);
  // 监听handle方法,保留原逻辑
  const spy = jest.spyOn(instance, 'handle');

  // 创建测试用Profile
  const { body } = await request(app.getHttpServer())
    .post('/profile')
    .send({ name: 'John Doe' })
    .expect(201);

  // 发起更新请求
  await request(app.getHttpServer())
    .put(`/profile/${body.id}`)
    .send({ name: 'Fulano de tal' })
    .expect(200);

  // 等待handle函数被调用且执行完成
  await waitFor(async () => {
    // 确认handle已被调用
    expect(spy).toHaveBeenCalled();
    // 检查handle的异步执行结果是否已resolved
    const handleResult = spy.mock.results[0].value;
    await expect(handleResult).resolves.toBeDefined(); // 根据实际返回值调整
  });

  // 这里可以添加对外部服务状态的检查逻辑
});

方法2:自定义标记跟踪监听函数完成状态

直接修改监听函数的实现,添加一个完成标记,测试时等待该标记变为true。

it("should be able to notify external service about profile update", async () => {
  const instance = app.get(NotifyExternalServiceAboutProfile);
  let isUpdateCompleted = false;
  // 保存原handle方法,后续恢复
  const originalHandle = instance.handle;

  // 重写handle方法,执行完原逻辑后标记完成
  instance.handle = async (...args) => {
    await originalHandle.apply(instance, args);
    isUpdateCompleted = true;
  };

  // 创建测试用Profile
  const { body } = await request(app.getHttpServer())
    .post('/profile')
    .send({ name: 'John Doe' })
    .expect(201);

  // 发起更新请求
  await request(app.getHttpServer())
    .put(`/profile/${body.id}`)
    .send({ name: 'Fulano de tal' })
    .expect(200);

  // 等待标记变为true
  await waitFor(() => {
    expect(isUpdateCompleted).toBe(true);
  });

  // 恢复原handle方法
  instance.handle = originalHandle;

  // 检查外部服务状态
});

方法3:利用EventEmitter的异步返回特性(v2+版本)

如果使用的是@nestjs/event-emitter v2及以上版本,emit方法会返回一个Promise,当所有监听函数执行完成后才会resolve。可以在测试中重写emit方法,确保等待所有监听逻辑完成。

it("should be able to notify external service about profile update", async () => {
  const eventEmitter = app.get(EventEmitter2);
  const originalEmit = eventEmitter.emit;

  // 重写emit方法,等待所有监听函数执行完成
  eventEmitter.emit = async (eventName, ...args) => {
    const listeners = eventEmitter.listeners(eventName);
    // 等待所有监听函数的异步逻辑完成
    await Promise.all(listeners.map(listener => listener(...args)));
    return originalEmit.call(eventEmitter, eventName, ...args);
  };

  // 创建测试用Profile
  const { body } = await request(app.getHttpServer())
    .post('/profile')
    .send({ name: 'John Doe' })
    .expect(201);

  // 发起更新请求,此时内部触发的事件会被等待完成
  await request(app.getHttpServer())
    .put(`/profile/${body.id}`)
    .send({ name: 'Fulano de tal' })
    .expect(200);

  // 直接检查外部服务状态即可

  // 恢复原emit方法
  eventEmitter.emit = originalEmit;
});

内容的提问来源于stack exchange,提问作者Thalles Passos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 00:53:31