在 React 功能组件中使用 ref 添加测试鼠标事件监听器
Posted
技术标签:
【中文标题】在 React 功能组件中使用 ref 添加测试鼠标事件监听器【英文标题】:Testing mouse event listener added using ref in React functional component 【发布时间】:2021-02-15 04:14:36 【问题描述】:您好,我有一个如下所示的功能组件:
import React, useRef, useEffect, useState from 'react';
const SomeComponent = ( prop1, ...otherProps) =>
const divRef = useRef();
useEffect(() =>
divRef.current.addEventListener('mousedown', mouseDownFunc);
, []);
const mouseDownFunc = () =>
document.addEventListener('mousemove', (el) =>
// call some parent function
);
return (
<div
className='test-div'
ref= divRef >
</div>
);
;
如何测试一个反应功能组件,其中 addEventListener 是使用 useEffect 中的 ref 添加的,当触发时调用 mouseDownFunc。 我是新来的反应笑话测试,对如何做有点困惑。
【问题讨论】:
你尝试了什么?您使用 addEventListener 而不是 React 事件有什么具体原因吗? 【参考方案1】:测试这种组件可能会很棘手,但使用@testing-library/react
我想我能够想出一些有用的东西。
我确实必须对您的组件进行一些更改以稍微公开 API,并且我还进行了一些更改,以便它停止侦听 mouseup
上的事件,这可能不是您想要的特定事件。
这是修改后的组件:
// MouseDownExample.js
import React, useEffect, useState from "react";
export default ( onMouseMoveWhileDown ) =>
const [x, setX] = useState(null);
const [listening, setListening] = useState();
// Replaced with mouse move function, should make sure we're unlistening as well
useEffect(() =>
if (listening)
const onMouseMove = (event) =>
// call some parent function
onMouseMoveWhileDown(event);
console.log(event.clientX);
// purely for testing purposes
setX(event.clientX);
;
const onMouseUp = (event) =>
// stop listening on mouse up
// - you should pick whatever event you want to stop listening
// - this is global so it also stops when the mouse is outside the box
setListening(false);
;
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
return () =>
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
;
, [listening, onMouseMoveWhileDown]);
return (
<div
style=
backgroundColor: "red",
width: 200,
height: 200
className="test-div"
onMouseDown=() =>
// moved this inline, so no ref
setListening(true);
>
X Position: x
</div>
);
;
我在 cmets 中指出了主要区别。
这是一个示例测试:
// MouseDownExample.test.js
import React from "react";
import fireEvent, render from "@testing-library/react";
import MouseDownExample from "./MouseDownExample";
it("shouldn't trigger onMouseMoveWhileDown when mouse isn't down", () =>
const onMouseMoveWhileDown = jest.fn();
const container = render(
<MouseDownExample onMouseMoveWhileDown=onMouseMoveWhileDown />
);
// Note: normally I would use `screen.getByRole` but divs don't have a useful role
const subject = container.firstChild;
fireEvent.mouseMove(
document,
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent
clientX: 200
);
// hasn't gone down yet
expect(onMouseMoveWhileDown).not.toHaveBeenCalled();
fireEvent.mouseDown(subject);
fireEvent.mouseUp(subject);
// went down then up before moving
fireEvent.mouseMove(document,
clientX: 200
);
expect(onMouseMoveWhileDown).not.toHaveBeenCalled();
);
it("should trigger onMouseMoveWhileDown when mouse is down", () =>
const onMouseMoveWhileDown = jest.fn();
const container = render(
<MouseDownExample onMouseMoveWhileDown=onMouseMoveWhileDown />
);
// Note: normally I would use `screen.getByRole` but divs don't have a useful role
const subject = container.firstChild;
fireEvent.mouseDown(subject);
fireEvent.mouseMove(document,
clientX: 200
);
expect(onMouseMoveWhileDown).toHaveBeenCalledWith(
expect.objectContaining( clientX: 200 )
);
);
这里发生了什么,我们正在渲染组件,然后触发事件以确保在我们期望的时候调用 onMouseMoveWhileDown
函数属性。
我们必须做expect.objectContaining
而不仅仅是对象,因为它是用包含其他属性的MouseEvent
调用的。
我们可能要添加的另一个测试是卸载测试,以确保侦听器不再触发事件。
你可以用这个Code Sandbox 这个组件和测试来查看/实验。希望对你有帮助?
【讨论】:
如果您对所做的修改有任何问题,请 lmk 我们可以解决/尝试找出如何在不进行更改的情况下进行测试以上是关于在 React 功能组件中使用 ref 添加测试鼠标事件监听器的主要内容,如果未能解决你的问题,请参考以下文章
使用 react-router-dom 时如何避免“功能组件不能被赋予 refs”?
React 功能组件 - 当组件返回元素数组时,如何将 refs 传递回父级?
处理用 TypeScript 编写的 React 功能组件中的 Ref:Element is not assignable 错误