Vue+Jest测试:Promise抛异常后验证Toast错误提示失败
问题分析与解决方案
核心问题点
- 组件内Toast调用对象不一致:你的
deleteUser方法中,成功回调用this.$toast.open,但异常回调误用了this.$st.toast.open,导致测试断言的对象与实际调用对象不匹配。 - 异步函数Mock方式错误:异常场景中直接同步抛出错误,而
fontService.deleteUser作为异步方法应该返回Promise,同步抛错无法被Promise的catch块捕获。 - 测试断言与Mock对象不匹配:成功场景中Mock了
wrapper.vm.$toast.open,但断言的却是wrapper.vm.$st.toast.open,属于笔误;异常场景同样存在这个问题。
修复步骤
1. 修正组件方法的Toast调用
将deleteUser方法中catch块的this.$st.toast改为this.$toast,保持和成功场景一致:
async deleteUser(userId) { this.setLoading(true); fontService .deleteUser(userId) .then(() => { this.$toast.open({ type: 'success', content: 'User was successfully deleted', }); this.getFonts(); }) .catch(() => { // 修正此处的$st.toast为$toast this.$toast.open({ type: 'error', content: 'There was an error trying to delete this font. Please try again.', }); }) .finally(() => { this.setLoading(false); }); }
2. 修正异常场景的Mock方式
使用mockRejectedValueOnce返回一个rejected状态的Promise,而不是同步抛错:
it('shows an error toast trying to delete', async () => { // 用mockRejectedValueOnce模拟异步方法抛出异常 jest.spyOn(fontService, 'deleteUser').mockRejectedValueOnce(new Error('error')); const wrapper = await createWrapper(); // 统一Mock$toast.open wrapper.vm.$toast.open = jest.fn(); // await异步方法,确保Promise链执行完成 await wrapper.vm.deleteUser('my_user_id'); expect(wrapper.vm.$toast.open).toBeCalledWith({ type: 'error', content: 'There was an error trying to delete this font. Please try again.', }); });
3. 修正成功场景的断言对象
成功场景中同样需要将断言对象改为wrapper.vm.$toast.open,与Mock对象保持一致:
it('shows a success toast after delete', async () => { jest.spyOn(fontService, 'deleteUser').mockResolvedValueOnce(true); const wrapper = await createWrapper(); wrapper.vm.$toast.open = jest.fn(); await wrapper.vm.deleteUser('my_user_id'); expect(wrapper.vm.$toast.open).toBeCalledWith({ type: 'success', content: 'User was successfully deleted', }); });
额外说明
- 对于异步方法的测试,直接
await方法调用比仅await $nextTick更可靠,因为它会等待整个Promise链的所有微任务执行完成。 - 如果你的项目中使用了
@vue/test-utils,也可以使用flushPromises()辅助函数来确保所有异步操作完成。
内容的提问来源于stack exchange,提问作者Marcelo J Forclaz
相关产品推荐
相关产品推荐

