You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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,再获取更新后的状态进行断言,具体步骤如下:

  1. 修正props更新方式:原代码中通过prop('paymentSchedule')(paymentSchedule)更新props的方式有误,应使用Enzyme的setProps方法直接更新组件props。
  2. 强制触发重渲染:调用container.update()确保React完成useEffect执行和状态更新。
  3. 断言状态值:通过组件实例的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 02:20:38