如何用Jest和Enzyme测试useEffect更新后的React状态值?
如何用Jest和Enzyme测试useEffect执行后的状态变化?
需求
测试useEffect执行后的组件状态变化。
组件代码(FooView.jsx)
const [total, setTotal] = useState(0); useEffect(() => { const calculatedTotal = calculateTotal(page.paymentSchedule); setTotal(calculatedTotal); }, [page.paymentSchedule]);
注:原代码中
calculatedTotal未声明,此处补充const修正语法问题。
测试代码片段(FooView-test.jsx)
describe('FooView', () => { const paymentSchedule = [ { count: 2, amount: 100, }, { count: 3, amount: 200, } ]; it('should update total when the payment schedule changes', () => { const container = mount(<FooView />); container.find('FooView').prop('paymentSchedule')(paymentSchedule); // what to do next }); });
解决方案
要测试useEffect执行后的状态,需确保props更新后触发useEffect,再获取更新后的状态进行断言,具体步骤如下:
- 修正props更新方式:原代码中通过
prop('paymentSchedule')(paymentSchedule)更新props的方式有误,应使用Enzyme的setProps方法直接更新组件props。 - 强制触发重渲染:调用
container.update()确保React完成useEffect执行和状态更新。 - 断言状态值:通过组件实例的
state()方法获取内部状态,或断言DOM中渲染的状态结果。
完整测试代码
describe('FooView', () => { const paymentSchedule = [ { count: 2, amount: 100, }, { count: 3, amount: 200, } ]; // 计算预期结果:2*100 + 3*200 = 800 const expectedTotal = 800; it('should update total when the payment schedule changes', () => { const container = mount(<FooView />); // 更新paymentSchedule props container.setProps({ paymentSchedule }); // 强制更新,确保useEffect执行并更新状态 container.update(); // 断言状态值 expect(container.find('FooView').state('total')).toBe(expectedTotal); }); });
关键说明
setProps的作用:更新组件props后,会触发useEffect的依赖(page.paymentSchedule)变化,进而执行useEffect逻辑。container.update()的必要性:Enzyme的mount组件不会自动同步React的状态更新,调用update()可以强制组件刷新,确保状态已更新。- DOM断言替代方案:如果
total值渲染到了DOM中(比如有<span className="total">{total}</span>),也可以通过DOM元素断言:expect(container.find('.total').text()).toBe(String(expectedTotal));
可选优化:Mock外部计算函数
如果calculateTotal是外部依赖函数,建议mock它,让测试更聚焦于组件逻辑,而非计算函数本身:
// 导入并mock calculateTotal import { calculateTotal } from './utils'; jest.mock('./utils', () => ({ calculateTotal: jest.fn(() => 800) })); describe('FooView', () => { // ... 测试代码 ... it('should update total when the payment schedule changes', () => { const container = mount(<FooView />); container.setProps({ paymentSchedule }); container.update(); expect(calculateTotal).toHaveBeenCalledWith(paymentSchedule); expect(container.find('FooView').state('total')).toBe(800); }); });
内容的提问来源于stack exchange,提问作者Christos Loupassakis
相关产品推荐
相关产品推荐

