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

如何在React Enzyme测试中设置ref.current的clientHeight和scrollHeight

问题解决:测试中触发依赖ref尺寸判断的元素渲染及回调

先纠正组件代码里的关键错误

你的组件存在3处错误,会直接导致尺寸判断逻辑失效:

  1. React.CreateRef() → 改为 React.createRef()(注意小写c,React API为驼峰小写开头)
  2. ref.current.ScrollHeight → 改为 ref.current.scrollHeight(DOM属性为驼峰小写开头)
  3. 泛型类型错误:React.RefObject<HTMLInputElement> → 改为 React.RefObject<HTMLDivElement>(你绑定ref的是<div>而非<input>)

修正后的组件核心代码:

import React, { useState, useLayoutEffect, createRef } from "react";

interface MyComponentProps {
  myCallBack: () => void;
}

const MyComponent = (props: React.PropsWithChildren<MyComponentProps>) => {
    const ref: React.RefObject<HTMLDivElement> = createRef();
    const { myCallBack } = props;
    const [showItem, setShowItem] = useState(false);

    useLayoutEffect(() => {
        if (ref.current && ref.current.clientHeight < ref.current.scrollHeight) {
            setShowItem(true);
        }
    }, [ref]);

    const someAction = (e: React.MouseEvent) => { // 修正事件类型,onClick对应MouseEvent
        myCallBack();
    }

    return(
        <div>
            <div ref={ref}>
                <p>Some text...</p>
            </div>
            {showItem && <div><p className="some-class" onClick={someAction}>Some more text...</p></div>} {/* 注意className而非class */}
        </div>
    );
}

export default MyComponent;

测试中设置ref元素的尺寸属性

要让测试里的showItem变为true,需要让ref元素的clientHeight小于scrollHeight,以下是几种可行方案:

方案一:mount后手动修改ref属性并触发更新

在mount组件后,直接修改DOM元素的尺寸属性,再触发组件重新渲染以执行useLayoutEffect:

describe("my tests", () => { 
  it("triggers callback when clicking the rendered item", async () => {
    const myCallBackMock = jest.fn();
    const wrapper = mount(<MyComponent myCallBack={myCallBackMock} />);
    
    // 获取绑定ref的DOM元素
    const refElement = wrapper.find("div").at(0).getDOMNode() as HTMLDivElement;
    // 用Object.defineProperty设置不可枚举的DOM属性
    Object.defineProperty(refElement, "clientHeight", { value: 50 });
    Object.defineProperty(refElement, "scrollHeight", { value: 100 });
    
    // 触发组件重新渲染,让useLayoutEffect再次执行
    wrapper.setProps({});
    
    // 模拟点击并断言
    wrapper.find(".some-class").simulate("click");
    expect(myCallBackMock).toHaveBeenCalled();
  });
});

方案二:全局mockHTMLElement的尺寸属性

如果多个测试都需要模拟尺寸,可以在测试前后全局mock原型属性:

describe("my tests", () => { 
  beforeEach(() => {
    // 给所有HTMLElement实例设置默认尺寸
    Object.defineProperty(HTMLElement.prototype, "clientHeight", {
      writable: true,
      value: 50,
    });
    Object.defineProperty(HTMLElement.prototype, "scrollHeight", {
      writable: true,
      value: 100,
    });
  });

  afterEach(() => {
    // 清除mock,避免影响其他测试用例
    jest.restoreAllMocks();
  });

  it("triggers callback when clicking the rendered item", async () => {
    const myCallBackMock = jest.fn();
    const wrapper = mount(<MyComponent myCallBack={myCallBackMock} />);
    
    // 此时showItem已为true,直接模拟点击
    wrapper.find(".some-class").simulate("click");
    expect(myCallBackMock).toHaveBeenCalled();
  });
});

方案三:直接修改组件状态(快速验证回调逻辑)

如果仅需验证点击回调的触发逻辑,可跳过尺寸判断,直接修改组件内部状态:

describe("my tests", () => { 
  it("triggers callback when clicking the item", async () => {
    const myCallBackMock = jest.fn();
    const wrapper = mount(<MyComponent myCallBack={myCallBackMock} />);
    
    // 直接设置showItem为true,强制渲染目标元素
    wrapper.setState({ showItem: true });
    
    wrapper.find(".some-class").simulate("click");
    expect(myCallBackMock).toHaveBeenCalled();
  });
});

补充说明

你的测试代码存在拼写错误:stimulate → 应为simulate,这也是报错的直接原因之一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 11:45:57