React点击按钮后state未更新,Enzyme+Jest测试失败如何解决?
问题原因
- wrapper初始化时机错误:你当前把
wrapper = shallow(<App />)写在describe根层级,执行时机早于beforeEach,首次渲染组件时你对React.useState的mock还没生效,用的还是原生React的useState逻辑。 - mock的useState无法触发状态更新与重渲染:你自定义mock的useState返回的setState是无逻辑的空模拟函数,调用它不会修改对应的state返回值,也不会触发组件重渲染,因此即使你模拟点击按钮触发了setState调用,组件的渲染内容也不会更新,h2自然还是初始的
default值。 - 全局初始化的wrapper没有在每个测试用例前重新生成,后续mock的useState逻辑完全没有作用到你测试用的wrapper实例上。
解决方案
你要同时满足「保留useState mock测试状态调用逻辑」和「验证点击后UI更新」两个需求,更推荐拆分测试用例的方案,符合单测职责单一原则:
测试状态调用逻辑(保留mock)
这个测试不用验证UI,只验证点击按钮后对应的setter是否被传入了预期参数:
describe('Test main component', () => { let wrapper; let setState; let setLoading; let setName; beforeEach(() => { setState = jest.fn(); setLoading = jest.fn(); setName = jest.fn(); // 先mock useState再渲染组件 React.useState = jest.fn() .mockImplementationOnce(initialState => [initialState, setState]) .mockImplementationOnce(initialState => [initialState, setLoading]) .mockImplementationOnce(initialState => [initialState, setName]) wrapper = shallow(<App />); }); afterEach(() => { jest.clearAllMocks(); }); // 只测setter调用逻辑 test('should call correct state setters when button clicked', () => { wrapper.find("button").simulate("click"); expect(setState).toHaveBeenCalledWith('changed'); expect(setLoading).toHaveBeenCalledWith(true); }) })
测试UI更新(不用mock useState,用真实状态)
验证渲染结果直接用组件原生的useState逻辑即可,Enzyme的shallow渲染会自动处理状态更新后的重渲染:
test('should change h2 text when button clicked', () => { // 不mock useState,直接渲染组件 const wrapper = shallow(<App />); wrapper.find("button").simulate("click"); expect(wrapper.find('h2').text()).toBe('changed'); })
如果你一定要在同一个测试用例里同时测,需要修改mock实现让useState和原生行为保持一致,用闭包存储状态、调用setter时主动触发重渲染即可,但这种方案模拟成本高,不推荐优先使用。
内容的提问来源于stack exchange,提问作者Asking
相关产品推荐
相关产品推荐

