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

如何用Jest+Enzyme测试Props传入状态更新函数的React组件

核心问题

你当前的测试思路存在偏差,不需要模拟React内置的useState Hook,问题本质是你对受控组件的测试逻辑理解错了:

  • 你写的Switch是标准受控组件,状态所有权属于父组件,组件本身只负责接收state展示状态、触发点击时调用父组件传入的setState,自身内部不应该持有同名状态,你在测试里调用wrapper.state("state")读取组件内部状态,从测试逻辑上就错了。
  • 你把wrapper.simulate、初始状态读取的逻辑写在了describe块的根作用域,这些代码会在所有用例执行前、beforeEach挂载组件之前运行,执行时序完全错误,大概率会拿不到挂载好的组件实例。
  • 你挂载组件时没有传入必填的state、setState两个props,不符合组件本身的使用要求。
正确测试方案

受控组件的单元测试不需要mock Hook,只需要验证两个核心行为即可:

  1. 组件接收到不同的state prop时,渲染的UI状态符合预期
  2. 用户点击组件时,会调用传入的setState prop,参数为当前state取反后的值

基础写法(推荐,执行快、用例隔离性好)

直接传入mock函数和可控的state值即可,不需要额外包裹组件:

import Switch from "./index";
import { mount, ReactWrapper } from "enzyme";

describe("[UNIT] Testing Switch component", () => {
  let wrapper: ReactWrapper;
  const mockSetState = jest.fn();

  beforeEach(() => {
    // 每个用例执行前重置mock记录,传入符合要求的props
    mockSetState.mockClear();
    wrapper = mount(<Switch state={false} setState={mockSetState} />);
  });

  it('should trigger setState with toggled value on click', () => {
    wrapper.simulate("click");
    // 验证setState被正确调用,参数为当前state的反值
    expect(mockSetState).toHaveBeenCalledTimes(1);
    expect(mockSetState).toHaveBeenCalledWith(true);
  });

  it('should render matching UI based on state prop', () => {
    // 初始state为false时的UI校验,根据你组件的实际DOM结构调整选择器
    expect(wrapper.find('[aria-checked="true"]').exists()).toBe(false);
    
    // 更新传入的state prop,验证UI同步更新
    wrapper.setProps({ state: true });
    wrapper.update();
    expect(wrapper.find('[aria-checked="true"]').exists()).toBe(true);
  });
});

真实场景模拟写法

如果你需要模拟真实父组件的状态流转,可以写一个极简的测试父组件,直接用真实的useState,不需要任何mock:

import { useState } from "react";
import { act } from "react-dom/test-utils";

// 模拟实际业务中使用Switch的父组件
const TestContainer = () => {
  const [switchVal, setSwitchVal] = useState(false);
  return <Switch state={switchVal} setState={setSwitchVal} />;
};

it('should toggle state correctly in real parent-child flow', () => {
  const wrapper = mount(<TestContainer />);
  // 校验初始状态
  expect(wrapper.find(Switch).prop("state")).toBe(false);
  
  // 触发点击,状态更新需要包裹在act中避免警告
  act(() => {
    wrapper.find(Switch).simulate("click");
  });
  wrapper.update();
  
  // 校验状态更新后的值
  expect(wrapper.find(Switch).prop("state")).toBe(true);
});

注意:所有触发React状态更新的操作,建议包裹在act()回调中执行,保证状态更新完成、DOM重渲染后再执行断言,避免出现测试结果不稳定的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 12:48:15