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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:35:21