Enzyme mount测试Redux状态更新失败问题排查
问题分析与解决方案
你的问题核心在于异步操作的时序问题——测试代码在点击按钮后立刻执行断言,但此时moxios拦截的异步请求还未完成,Redux状态还没更新,组件也没有重新渲染,所以expect(wrapped.find("li").length).toBe(2)会失败。你看到的console.log输出其实是在测试跑完之后异步执行的,所以测试断言早于组件更新完成。
为什么会出现这种情况?
- 点击按钮触发
fetchComments,这个action返回的是一个处于pending状态的Promise(由axios.get创建)。 redux-promise中间件会等待这个Promise resolve后,才会分发真正的FETCH_COMMENTSaction去更新Redux状态。- 你的测试代码在点击后直接调用
wrapped.update()并断言,这时候Promise还未resolve,状态还是初始的空数组,组件自然不会渲染<li>元素。
解决方案:等待异步操作完成
我们需要让测试等待moxios处理完请求、Redux状态更新、组件重新渲染后再执行断言。以下两种方式都可以实现:
方式一:使用moxios.wait()结合done回调
修改你的integration.test.js测试代码:
it("can fetch a list of comments and display them", (done) => { // 渲染整个应用 const wrapped = mount( <Root> <CommentList /> </Root> ); // 找到按钮并模拟点击 wrapped.find(".fetch-comments").simulate("click"); // 等待moxios处理完所有待请求 moxios.wait(() => { // 强制组件更新,确保状态变更反映到DOM上 wrapped.update(); // 此时断言就能拿到正确结果 expect(wrapped.find("li").length).toBe(2); // 清理组件避免内存泄漏 wrapped.unmount(); // 通知Jest测试完成 done(); }); });
方式二:使用async/await语法
如果更习惯异步函数的写法,也可以这样修改:
it("can fetch a list of comments and display them", async () => { // 渲染整个应用 const wrapped = mount( <Root> <CommentList /> </Root> ); // 找到按钮并模拟点击 wrapped.find(".fetch-comments").simulate("click"); // 等待moxios处理请求 await moxios.wait(); // 强制组件更新 wrapped.update(); // 执行断言 expect(wrapped.find("li").length).toBe(2); // 清理组件 wrapped.unmount(); });
补充说明
你的mock store测试能通过,是因为初始状态直接设置了comments数组,组件是同步渲染出<li>元素的,没有异步等待的问题。测试后记得调用wrapped.unmount()清理组件,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Hylle
相关产品推荐
相关产品推荐

