Selenium调用dragAndDrop无法触发onDragEnter事件问题问询
Selenium触发
.onDragEnter拖拽事件失效问题 要触发.onDragEnter函数,在HTML5拖拽场景下使用Selenium原生API会出现失效问题。
你当前使用的实现代码如下:
// 初始化 // 打开页面,等待加载完成 const actions = await driver.actions(); const da1 = await driver.findElement(By.css('#todrag > span')); const da2 = await driver.findElement(By.css('#mydropzone')); await actions.dragAndDrop(da1, da2).perform();
.dragAndDrop()方法运行无效,分步实现也存在相同问题:
await actions.move({origin: da1}).press().move({origin: da2}).release().perform();
异常表现
- 该问题属于Selenium原生actions API未修复的已知Bug
.perform()执行后点击鼠标左键偶发卡顿,真实鼠标指针上会生成[Draggable 1]的拖拽对象
已有疑问回复
cruisepandey 提问:你确定没有漏掉.build.perform()调用吗?
实测各写法报错如下:
.build.perform(); 报错:TypeError: Cannot read property 'perform' of undefined .build().perform(); 报错:TypeError: actions.dragAndDrop(...).build is not a function .build.perform(); 报错:TypeError: Cannot read property 'perform' of undefined .build().perform(); 报错:TypeError: actions.move(...).press(...).move(...).release(...).build is not a function
解决方案
该问题由Selenium原生actions API对HTML5拖拽事件的兼容性缺陷导致,可通过注入JavaScript模拟完整拖拽事件流解决,实现代码如下:
// 封装HTML5拖拽通用方法 async function html5DragAndDrop(sourceEl, targetEl) { const dragAndDropScript = ` function createEvent(type) { const event = document.createEvent("CustomEvent"); event.initCustomEvent(type, true, true, null); event.dataTransfer = { data: {}, setData: (key, value) => this.data[key] = value, getData: key => this.data[key] }; return event; } function dispatchEvent(el, event, transferData) { if (transferData) event.dataTransfer = transferData; el.dispatchEvent ? el.dispatchEvent(event) : el.fireEvent("on" + event.type, event); } const source = arguments[0], target = arguments[1]; const dragStart = createEvent("dragstart"); dispatchEvent(source, dragStart); dispatchEvent(target, createEvent("dragenter"), dragStart.dataTransfer); dispatchEvent(target, createEvent("dragover"), dragStart.dataTransfer); dispatchEvent(target, createEvent("drop"), dragStart.dataTransfer); dispatchEvent(source, createEvent("dragend"), dragStart.dataTransfer); `; await driver.executeScript(dragAndDropScript, sourceEl, targetEl); } // 调用方法 const da1 = await driver.findElement(By.css('#todrag > span')); const da2 = await driver.findElement(By.css('#mydropzone')); await html5DragAndDrop(da1, da2);
方案说明
- 直接在浏览器内核层面模拟完整的HTML5拖拽事件流,包含
dragstart、dragenter、dragover、drop、dragend全节点事件触发,可正常命中.onDragEnter回调 - 完全绕过Selenium原生actions API的已知拖拽缺陷,兼容性覆盖所有支持HTML5标准的拖拽场景
- 不需要修改原有元素定位逻辑,直接传入已获取的源元素和目标元素即可调用
内容的提问来源于stack exchange,提问作者Vadim
相关产品推荐
相关产品推荐

