使用Jest和Enzyme测试React组件遇act警告及断言失败求助
问题排查与解决方案
你的问题核心在于异步操作未被act完整包裹,且Enzyme的组件状态未同步更新,导致断言时机错误和act警告。
问题根源
- 组件的
onClick是异步函数,内部await getData()会将后续的setData和setIsLoading(false)放入微任务队列执行。你当前用void act()包裹的只是同步的点击触发,没有等待异步操作完成,React无法捕获后续的状态更新,因此抛出act警告。 - 异步操作完成后,Enzyme的mount wrapper不会自动刷新组件状态,你直接断言时拿到的还是旧的"loading"文本。
修复步骤
1. 将测试用例改为异步函数,用async/await配合act
需要用异步版的act包裹点击操作,并等待其完成,确保所有异步状态更新都被React捕获。
2. 同步Enzyme组件状态
异步操作完成后,调用component.update()刷新wrapper,确保获取到最新的组件DOM状态。
修改后的完整测试代码
import { mount } from 'enzyme'; import * as React from 'react'; import { act } from 'react-dom/test-utils'; const getData = async () => new Promise<string>((resolve) => resolve('data')); const Component: React.FC = () => { const [data, setData] = React.useState(''); const [isLoading, setIsLoading] = React.useState(true); const onClick = async () => { setIsLoading(true); try { const dataResponse = await getData(); setData(dataResponse); } catch (error) { console.error('getData failed', error); } setIsLoading(false); }; return ( <button onClick={onClick}> <p>{isLoading ? 'loading' : data}</p> </button> ); }; describe('Component', () => { // 改为异步测试用例 it('should render', async () => { const component = mount(<Component />); const button = component.find('button'); let paragraph = component.find('p'); expect(button).toBeDefined(); expect(paragraph).toBeDefined(); expect(paragraph.props().children).toBe('loading'); // 用async/await包裹act,等待异步操作完成 await act(async () => { button.simulate('click'); }); // 刷新组件状态 component.update(); // 重新获取最新的paragraph元素 paragraph = component.find('p'); expect(paragraph.props().children).toBe('data'); }); });
额外说明
- 如果你的项目中存在多个异步操作需要等待,也可以封装一个
flushPromises函数来快速清空微任务队列:
使用时在const flushPromises = () => new Promise(resolve => setImmediate(resolve));act之后调用await flushPromises(),再执行component.update()即可。 - 确保你的Enzyme版本支持React 16+的act集成,若版本较旧可能需要安装
enzyme-adapter-react-xx适配包并配置。
内容的提问来源于stack exchange,提问作者Vinay Sharma
相关产品推荐
相关产品推荐

