如何在React Enzyme测试中设置ref.current的clientHeight和scrollHeight
问题解决:测试中触发依赖ref尺寸判断的元素渲染及回调
先纠正组件代码里的关键错误
你的组件存在3处错误,会直接导致尺寸判断逻辑失效:
React.CreateRef()→ 改为React.createRef()(注意小写c,React API为驼峰小写开头)ref.current.ScrollHeight→ 改为ref.current.scrollHeight(DOM属性为驼峰小写开头)- 泛型类型错误:
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
相关产品推荐
相关产品推荐

