如何在React Testing Library中模拟鼠标offsetX与offsetY属性?
解决React Testing Library中模拟鼠标点击offsetX/offsetY的问题
你遇到的核心问题是userEvent.click默认不会传递offsetX/offsetY属性,而直接构造MouseEvent时这两个属性为只读,无法通过构造函数直接设置。下面是两种可行的解决方法:
方法一:使用fireEvent手动添加offset属性
MouseEvent构造函数不能直接设置offsetX/offsetY,但可以通过Object.defineProperty给事件对象手动添加这两个属性,同时要确保事件对象开启冒泡和可取消,否则React无法捕获到事件(这也是你之前用fireEvent没触发目标函数的原因)。示例代码:
it("validates if the user clicked on the correct spot", async () => { render( <MemoryRouter> <Game imgData={gameImgData} /> </MemoryRouter> ); const startBtn = screen.getByRole("button", { name: /start/i }); await userEvent.click(startBtn); const gameImg = screen.getByAltText("game-screen"); // 构造点击事件并添加offset属性 const clickEvent = new MouseEvent("click", { bubbles: true, cancelable: true, }); Object.defineProperty(clickEvent, "offsetX", { value: 400 }); Object.defineProperty(clickEvent, "offsetY", { value: 你的目标Y坐标 }); fireEvent(gameImg, clickEvent); expect(screen.getByText("You win!")).toBeInTheDocument(); });
方法二:使用userEvent的pointerClick指定坐标
userEvent的pointerClick方法支持通过clientX/clientY指定点击位置,你可以结合图片的DOM位置计算出对应offsetX/offsetY的坐标值,示例代码:
it("validates if the user clicked on the correct spot", async () => { render( <MemoryRouter> <Game imgData={gameImgData} /> </MemoryRouter> ); const user = userEvent.setup(); const startBtn = screen.getByRole("button", { name: /start/i }); await user.click(startBtn); const gameImg = screen.getByAltText("game-screen"); // 获取图片的DOM位置信息 const imgRect = gameImg.getBoundingClientRect(); // 计算对应offsetX=400时的clientX(假设图片无额外padding/border) const targetClientX = imgRect.left + 400; const targetClientY = imgRect.top + 你的目标Y坐标; await user.pointerClick(gameImg, { clientX: targetClientX, clientY: targetClientY }); expect(screen.getByText("You win!")).toBeInTheDocument(); });
如果图片有内边距或边框,需要在计算时额外调整偏移量。
额外建议:优化组件可测试性
如果需要频繁测试点击位置判断逻辑,可以把核心判断逻辑抽离成独立函数,这样测试时无需模拟点击事件,直接测试函数即可:
// 组件中抽离判断逻辑 function Game(image){ const checkVictory = (offsetX, offsetY) => { return offsetX === 400; // 返回判断结果 }; const handleClick = (e) => { if (checkVictory(e.offsetX, e.offsetY)) { console.log("You win!"); } }; return ( <main> <img src={image.src} alt="game-screen" onClick={handleClick} /> </main> ); } // 单独测试核心判断逻辑 it("checks victory correctly", () => { expect(checkVictory(400, 任意Y值)).toBe(true); expect(checkVictory(399, 任意Y值)).toBe(false); });
内容的提问来源于stack exchange,提问作者Alphatron
相关产品推荐
相关产品推荐

