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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 19:45:02