如何使用Jest测试含Promise逻辑的React函数组件行为
问题原因
测试执行失败的核心原因是异步逻辑的执行时机问题:aPromiseReturningFunction返回的Promise的then回调属于微任务,会在当前所有同步代码执行完毕后才会运行。你在触发click事件后立刻同步执行断言,此时then回调里的setState还未调用,组件state没有更新,渲染内容依旧是初始值12,因此断言不通过。
另外补充一个小问题:你的组件名myComponent首字母为小写,不符合React组件命名规范,React会将首字母小写的标签识别为原生DOM元素,可能引发额外的渲染或测试异常,建议修改为首字母大写的MyComponent。
解决方案
只需要调整测试代码,等待所有异步微任务执行完成,再执行断言即可,以下是两种常用实现方案:
方案1:直接等待微任务队列清空(无需额外依赖)
将测试函数改为异步函数,触发点击后await一个空的Promise,即可让所有已排队的微任务执行完毕,再调用update方法刷新shallow渲染的组件内容,再做断言:
test('点击后等待Promise resolve更新state', async () => { const myFunc = jest.fn(() => Promise.resolve(true)); const componentWrapper = shallow(<MyComponent aPromiseReturningFunction={myFunc} />); componentWrapper.simulate('click'); // 等待所有微任务执行完成 await Promise.resolve(); // 刷新shallow组件的渲染结果,同步最新state componentWrapper.update(); expect(componentWrapper.text()).toEqual('123'); });
方案2:搭配React官方的act工具(更符合测试规范)
使用React测试工具提供的act包裹所有会触发组件更新的操作,确保所有状态更新都完整应用到组件上,再做断言:
import { act } from 'react-dom/test-utils'; test('点击后等待Promise resolve更新state', async () => { const myFunc = jest.fn(() => Promise.resolve(true)); let componentWrapper; await act(async () => { componentWrapper = shallow(<MyComponent aPromiseReturningFunction={myFunc} />); componentWrapper.simulate('click'); }); componentWrapper.update(); expect(componentWrapper.text()).toEqual('123'); });
如果你的测试开启了Jest的模拟定时器,还需要额外调用jest.runAllTicks()或者jest.useRealTimers()配合使用,默认配置下上述两种方案都可以直接运行。
内容的提问来源于stack exchange,提问作者manosagent
相关产品推荐
相关产品推荐

