Vue.js与Jest:断言前等待Promise(含finally子句)完全执行的正确方法
解决Jest等待Vue组件Promise finally子句执行完成的问题
这个问题我之前也碰到过,核心原因是你测试中await的是原始的component.promise,但附加在它上面的then/catch/finally回调都是异步微任务。当原始Promise settle后,Jest会立刻执行后续断言,但此时这些回调可能还没被执行,导致ready仍然是false。下面给你几个不需要额外库的解决方案:
方案1:让myMethod返回链式调用的Promise(推荐)
修改组件的myMethod,让它返回then/catch/finally链式调用后的Promise,这样测试里可以直接等待整个异步流程完成:
private myMethod(): Promise<void> { return this.promise .then(() => { this.result = 1; }) .catch(() => { this.result = 2; }) .finally(() => { this.ready = true; }); }
然后在测试中直接await这个方法的执行(如果是测试点击逻辑,也可以通过trigger触发后等待,但更直接的是调用方法本身):
it('should set the result to 1 and be ready', async () => { // Given component.promise = Promise.resolve(); // When await component.myMethod(); // Then expect(component.result).toBe(1); expect(component.ready).toBe(true); }); it('should set the result to 2 and be ready', async () => { // Given component.promise = Promise.reject(); // When await component.myMethod(); // Then expect(component.result).toBe(2); expect(component.ready).toBe(true); });
这个方案不仅能解决测试问题,还让组件的异步行为更清晰,调用方也能更好地处理后续逻辑。
方案2:不修改组件代码,等待微任务队列清空
如果你不想修改组件代码,可以在await原始Promise之后,再await Promise.resolve(),这会迫使Jest等待当前所有已调度的微任务(包括then和finally的回调)执行完毕:
it('should set the result to 1 and be ready', async () => { // Given component.promise = Promise.resolve(); // When wrapper.find('#myButton').trigger('click'); await expect(component.promise).resolves.toBeUndefined(); await Promise.resolve(); // 等待所有微任务执行完成 // Then expect(component.result).toBe(1); expect(component.ready).toBe(true); }); it('should set the result to 2 and be ready', async () => { // Given component.promise = Promise.reject(); // When wrapper.find('#myButton').trigger('click'); await expect(component.promise).rejects.toBeUndefined(); await Promise.resolve(); // 等待微任务队列清空 // Then expect(component.result).toBe(2); expect(component.ready).toBe(true); });
方案3:使用Vue的$nextTick
Vue的$nextTick会等待Vue的响应式更新队列和所有微任务完成,也能达到同样的效果:
it('should set the result to 1 and be ready', async () => { // Given component.promise = Promise.resolve(); // When wrapper.find('#myButton').trigger('click'); await expect(component.promise).resolves.toBeUndefined(); await component.$nextTick(); // Then expect(component.result).toBe(1); expect(component.ready).toBe(true); });
不过这个方案依赖Vue的API,通用性不如方案2。
内容的提问来源于stack exchange,提问作者Eria
相关产品推荐
相关产品推荐

