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

使用Jest测试dnd-kit/sortable组件:排序功能测试失败

使用dnd-kit的拖拽排序组件测试问题

我正在为基于dnd-kit的拖拽排序组件编写测试用例,目前能成功触发dragStart和dragEnd行为,但尝试重新排序列表时,列表始终保持原有顺序。

触发拖拽行为的代码(需添加MouseSensor才能正常运行)

// mouse over dragged element and mousedown
act(() => {
  fireMouseEvent("mousemove", elemDrag, center1X, center1Y);
  sleep(1);
  fireMouseEvent("mouseenter", elemDrag, center1X, center1Y);
  sleep(1);
  fireMouseEvent("mouseover", elemDrag, center1X, center1Y);
  sleep(1);
  fireMouseEvent("mousedown", elemDrag, center1X, center1Y);
  sleep(1);
});

// start dragging process over to drop target
act(() => {
  const dragStarted = fireMouseEvent(
    "dragstart",
    elemDrag,
    center1X,
    center1Y
  );
  if (!dragStarted) {
    return;
  }
});

act(() => {
  fireMouseEvent("drag", elemDrag, center1X, center1Y);
  sleep(1);
  fireMouseEvent("mousemove", elemDrag, center1X, center1Y);
  sleep(1);
  fireMouseEvent("drag", elemDrag, center2X, center2Y);
  sleep(1);
  fireMouseEvent("mousemove", elemDrop, center2X, center2Y);

  // trigger dragging process on top of drop target
  fireMouseEvent("mouseenter", elemDrop, center2X, center2Y);
  sleep(1);
  fireMouseEvent("dragenter", elemDrop, center2X, center2Y);
  sleep(1);
  fireMouseEvent("mouseover", elemDrop, center2X, center2Y);
  sleep(1);
  fireMouseEvent("dragover", elemDrop, center2X, center2Y);
  sleep(1);


  // release dragged element on top of drop target
  fireMouseEvent("drop", elemDrop, center2X, center2Y);
  sleep(1);
  fireMouseEvent("dragend", elemDrag, center2X, center2Y);
  sleep(1);
  // fireMouseEvent("mouseup", elemDrag, center2X, center2Y);
  // sleep(1);
});

异常现象

注释掉最后一行的mouseup事件时,dnd-kit的辅助功能提示显示:Draggable item item-0 was moved over droppable area item-1.,且用jest-preview能预览到重新排序后的列表。但取消注释该行后,辅助功能提示变为:Draggable item item-0 was dropped over droppable area item-0,列表也不会排序。

获取元素及模拟矩形区域的代码

const draggables = container.querySelectorAll(
  '[aria-roledescription="sortable"]'
);

Object.setPrototypeOf(window, Window.prototype);
draggables.forEach((draggable, index) => {
  mockGetBoundingClientRect(draggable, index);
});

const elemDrag = draggables[0];
const elemDrop = draggables[1];

let pos = elemDrag.getBoundingClientRect();
const center1X = Math.floor((pos.left + pos.right) / 2);
const center1Y = Math.floor((pos.top + pos.bottom) / 2);
pos = elemDrop.getBoundingClientRect();
const center2X = Math.floor((pos.left + pos.right) / 2);
const center2Y = Math.floor((pos.top + pos.bottom) / 2) + 50;
jest.spyOn(element, "getBoundingClientRect").mockImplementation(() => ({
  bottom: 88 + index * (177 - 88),
  height: 48,
  left: 68,
  right: 282.078125,
  top: 40 + index * 89,
  width: 214.078125,
  x: 68,
  y: 40 + index * 89,
}));

可能的解决方向

  • 调整mouseup的触发目标:当前mouseup绑定在原拖拽元素elemDrag上,但拖拽过程中元素的逻辑落点应该是目标区域,试试把mouseup的触发目标改成elemDrop。
  • 修正事件执行顺序:dnd-kit的MouseSensor依赖严格的事件序列,正确顺序应为mousedown → 拖拽移动 → dragover目标 → drop → mouseup → dragend,你当前的dragend在mouseup之前,可能打乱了内部状态,调换两者顺序试试。
  • 检查坐标模拟:给center2Y额外加50可能导致拖拽元素未完全落在目标区域的有效范围内,尝试直接使用目标元素的中心坐标(去掉+50),或调整偏移值确保覆盖有效交互区域。
  • 简化事件序列:dnd-kit的MouseSensor核心依赖原生鼠标事件序列(mousedown/mousemove/mouseup),你添加的HTML原生拖拽事件(dragstart/drag/dragenter等)可能干扰自定义传感器逻辑,尝试移除这些多余事件,只保留鼠标事件序列。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:43:28