如何在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
相关产品推荐
相关产品推荐

