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

如何设置useState默认值并测试按钮点击满足条件时的state触发逻辑

问题排查与修复方案

核心问题点

  • 错误的useState全局模拟逻辑:组件内共有3次useState调用,当前mock将所有useState的返回值都固定为[false, mockSetSuccess],导致ingredients、ingredient两个状态的取值和更新逻辑完全失效,无法触发后续判断条件。
  • 测试场景不符合触发要求:业务逻辑要求ingredients长度为2时才会执行setSuccess(true),当前测试仅输入1次内容、点击1次按钮,ingredients最长只能到1,永远不会满足触发条件。
  • 状态更新顺序问题:业务代码中先判断ingredients.length === 2,再更新ingredients数组,因此需要第三次点击按钮时才会触发setSuccess(前两次点击分别把数组长度从0变1、1变2,第三次点击时判断长度为2才执行)。

修复后的测试代码

test("success state updated when click of the button", () => {
  // 按组件内useState调用顺序依次返回对应的状态和setter
  const mockSetSuccess = jest.fn();
  const mockIngredients = [];
  const mockSetIngredients = jest.fn((val) => mockIngredients.push(...val));
  const mockIngredient = { value: "" };
  const mockSetIngredient = jest.fn((val) => mockIngredient.value = val);

  React.useState = jest.fn((defaultVal) => {
    // 第一次调用useState对应success状态
    if (React.useState.mock.calls.length === 1) {
      return [false, mockSetSuccess];
    }
    // 第二次调用对应ingredients状态
    if (React.useState.mock.calls.length === 2) {
      return [mockIngredients, mockSetIngredients];
    }
    // 第三次调用对应ingredient状态
    return [mockIngredient.value, mockSetIngredient];
  });

  const wrapper = shallow(<App />);
  const input = wrapper.find("[data-test='app-input']");
  const button = wrapper.find("[data-test='app-button']");

  // 模拟三次输入+点击操作,凑够ingredients长度为2的触发条件
  for (let i = 0; i < 3; i++) {
    input.simulate("change", { target: { value: `test${i}` } });
    button.simulate("click", {});
  }

  expect(mockSetSuccess).toHaveBeenCalledWith(true);
});

优化建议

如果不想手动mock多组useState,更合理的测试方式是不模拟useState本身,直接测试组件行为:输入三次内容点击三次按钮后,校验success状态对应的UI表现(比如成功提示是否出现)即可,不需要直接mock内部hooks。

内容的提问来源于stack exchange,提问作者kumaran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 13:06:01