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

如何用React Testing Library和Jest测试含点击事件的useState与useEffect?

问题分析与解决方案

核心问题点

  1. useState Mock 实现错误:你的mock函数存在拼写错误(useSateMock → useStateMock),且返回值逻辑错误,没有正确返回组件的初始状态false。
  2. 测试用例逻辑矛盾:用例命名是验证初始状态为false,但代码中却触发了点击事件,还错误地期望setStateMock为falsy——实际上点击后setStateMock会被调用,是一个已执行的jest函数,不可能是falsy。
  3. useEffect 依赖数组错误:组件里的useEffect依赖是[""],这会导致每次组件渲染都重新绑定事件,应该改为空数组[]确保只在挂载/卸载时执行一次。

修正后的测试代码

测试初始状态

it("should have initial state false", () => {
  const setStateMock = jest.fn();
  // 正确mock useState,返回初始状态false和mock的set函数
  jest.spyOn(React, "useState").mockImplementation(() => [false, setStateMock]);

  render(<Dropdown placeholder="placeholder name" options={testOptions} />, { wrapper: BrowserRouter });
  
  // 验证初始状态下setState未被调用
  expect(setStateMock).not.toHaveBeenCalled();
  // 若要验证UI表现,可检查下拉菜单是否隐藏(假设下拉菜单有对应testId)
  // expect(screen.queryByTestId("dropdown-menu")).not.toBeInTheDocument();
});

测试点击后状态切换

it("should toggle showDropdown state when button is clicked", () => {
  let currentState = false;
  const setStateMock = jest.fn((newState) => {
    currentState = newState;
  });
  jest.spyOn(React, "useState").mockImplementation(() => [currentState, setStateMock]);

  render(<Dropdown placeholder="placeholder name" options={testOptions} />, { wrapper: BrowserRouter });
  const dropdownBtn = screen.getByTestId("dropdownBtn");
  
  fireEvent.click(dropdownBtn);
  // 验证setState被调用,且参数为true(初始false取反)
  expect(setStateMock).toHaveBeenCalledWith(true);
  // 或者直接验证当前状态已变为true
  expect(currentState).toBe(true);
});

组件代码优化(非测试相关,但建议修正)

把useEffect的依赖数组从[""]改为[],避免不必要的事件绑定/解绑:

useEffect(() => {
  const handler = () => setShowDropdown(false);

  window.addEventListener("click", handler);
  return () => {
    window.removeEventListener("click", handler);
  };
}, []); // 改为空数组

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 09:05:23