转载请注明出处️

作者:测试蔡坨坨

原文链接:caituotuo.top/e8aa6c6f.html


你好,我是测试蔡坨坨。

前几天在使用Selenium进行元素拖拽操作时,发现Selenium自带的元素拖拽方法(dragAndDrop())不生效,网上的回答也是五花八门,比较混乱,尝试了以下几种方法均无法解决

方案1:通过dragAndDrop()方法将元素拖放到特定区域上——无效

// 要拖拽的元素
WebElement draggable = driver.findElement(By.xpath(""));
// 目标元素/区域
WebElement droppable = driver.findElement(By.xpath(""));
new Actions(driver).dragAndDrop(draggable, droppable).build().perform();

方案2:通过dragAndDropBy()方法将元素进行指定像素位移,从而实现拖放到特定区域,该方法需要先找到元素的像素——无效

new Actions(driver).dragAndDropBy(draggable,135, 40).build().perform();

方案3:先通过clickAndHold()方法点击并按住元素,然后使用moveByOffset()方法将元素拖拽到目标区域,再使用release()方法将按住的元素释放——无效

new Actions(driver).clickAndHold(draggable).moveByOffset(400, 0).release().build().perform();

方案4:先通过clickAndHold()方法点击并按住元素,然后使用moveToElement()方法将元素拖拽到指定元素上,再使用release()方法将元素释放——无效

new Actions(driver).clickAndHold(draggable).moveToElement(droppable).release(droppable).build().perform();

方案5:借助Robot类实现拖拽——无效

Point coordinates1 = draggable.getLocation();
Point coordinates2 = droppable.getLocation();
Robot robot = new Robot();
robot.mouseMove(coordinates1.getX(), coordinates1.getY());
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseMove(coordinates2.getX(), coordinates2.getY());
robot.mouseRelease(InputEvent.BUTTON1_MASK);

……

以上方案均未生效,具体表现为运行均无任何报错,但在应用程序中未发生拖放。

经过一顿操作,最终在「Selenium Drag and Drop Bug Workaround」上找到了问题原因及解决方案。

经了解,Selenium的拖放功能在某些情况下无效的错误已经存在多年。

原因是拖放功能包含三个动作:单击并按住(click and hold)、将鼠标移动到其他元素或位置(move mouse to other element/location)、释放鼠标(release mouse),问题在于最后一步释放鼠标的操作,当Webdriver API发送释放鼠标的请求时,在某些情况下它会一直按住它,所以导致拖放功能无效。

解决方法就是通过Webdriver API将JavaScript代码发送到浏览器,利用JavaScript模拟拖放操作,而不使用Webdriver自带的拖放方法。

其工作原理是将浏览器实例和CSS选择器找到的两个Web元素作为参数,然后在浏览器端执行JavaScript代码。

如果你是使用Python+Selenium技术栈实现的Web UI自动化,可以直接下载seletools(Selenium Tools,作者:Dmitrii Bormotov)包,并将它导入到需要执行拖放的地方,然后简单地调用它的drag_and_drop()方法即可。

pip install seletools
from seletools.actions import drag_and_drop

source = driver.find_element(By.CSS_SELECTOR, "#column-a")
target = browser.find_element(By.CSS_SELECTOR, "#column-b")
drag_and_drop(driver, source, target)

如果使用的是Java+Selenium技术栈,则可以使用以下代码实现:

// 要拖拽的元素
WebElement draggable = driver.findElement(By.xpath(""));
// 目标元素
WebElement droppable = driver.findElement(By.xpath("")); // 拖动前先点击并按住要拖拽的元素,避免在elementui,拖放前draggable属性才会变成true,目的是让draggable变成true,如果一开始就是true也可不加这句
new Actions(driver).clickAndHold(draggable).perform(); final String java_script = "var args = arguments," + "callback = args[args.length - 1]," + "source = args[0]," + "target = args[1]," + "offsetX = (args.length > 2 && args[2]) || 0," + "offsetY = (args.length > 3 && args[3]) || 0," + "delay = (args.length > 4 && args[4]) || 1;" + "if (!source.draggable) throw new Error('Source element is not draggable.');" + "var doc = source.ownerDocument," + "win = doc.defaultView," + "rect1 = source.getBoundingClientRect()," + "rect2 = target ? target.getBoundingClientRect() : rect1," + "x = rect1.left + (rect1.width >> 1)," + "y = rect1.top + (rect1.height >> 1)," + "x2 = rect2.left + (rect2.width >> 1) + offsetX," + "y2 = rect2.top + (rect2.height >> 1) + offsetY," + "dataTransfer = Object.create(Object.prototype, {" + " _items: { value: { } }," + " effectAllowed: { value: 'all', writable: true }," + " dropEffect: { value: 'move', writable: true }," + " files: { get: function () { return undefined } }," + " types: { get: function () { return Object.keys(this._items) } }," + " setData: { value: function (format, data) { this._items[format] = data } }," + " getData: { value: function (format) { return this._items[format] } }," + " clearData: { value: function (format) { delete this._items[format] } }," + " setDragImage: { value: function () { } }" + "});" + "target = doc.elementFromPoint(x2, y2);" + "if(!target) throw new Error('The target element is not interactable and need to be scrolled into the view.');" + "rect2 = target.getBoundingClientRect();" + "emit(source, 'dragstart', delay, function () {" + "var rect3 = target.getBoundingClientRect();" + "x = rect3.left + x2 - rect2.left;" + "y = rect3.top + y2 - rect2.top;" + "emit(target, 'dragenter', 1, function () {" + " emit(target, 'dragover', delay, function () {" + "\ttarget = doc.elementFromPoint(x, y);" + "\temit(target, 'drop', 1, function () {" + "\t emit(source, 'dragend', 1, callback);" + "});});});});" + "function emit(element, type, delay, callback) {" + "var event = doc.createEvent('DragEvent');" + "event.initMouseEvent(type, true, true, win, 0, 0, 0, x, y, false, false, false, false, 0, null);" + "Object.defineProperty(event, 'dataTransfer', { get: function () { return dataTransfer } });" + "element.dispatchEvent(event);" + "win.setTimeout(callback, delay);" + "}"; // 默认拖拽到中心点位置,第3个参数是X坐标偏移量(左负右正),第4个参数为Y坐标偏移量(上负下正),第5个参数是延迟时间(单位为毫秒,表示当鼠标点下后,延迟指定时间后才开始激活拖拽动作,用来防止误点击)
((JavascriptExecutor) driver).executeScript(java_script, draggable, droppable, -200, -300, 500);

以上就是在Python和Java中的解决方案,至于为什么不在Selenium中直接修改程序,而是创建单独的包来处理,以下是Dmitrii Bormotov的说法:

The drag and drop bug is a webdriver issue, so all you can do on the Selenium side is to simply perform the same workaround that I did. I spoke with David Burnes (core Selenium committer) about pushing that workaround into Selenium, but he said that it is not a good idea to have any workarounds in Selenium itself. That is why I had to create a separate package to help the test automation community with this problem.

大概的意思就是拖放错误是一个webdriver网络驱动问题,David Burnes(核心 Selenium 提交者)认为在Selenium中提供任何暂时避开网络的方法并不是一个好主意。

解决Selenium元素拖拽不生效Bug的更多相关文章

  1. Selenium - 实现网页元素拖拽

    Drag and Drop, 使用鼠标实现元素拖拽的操作貌似很复杂, 在Selenium中, 借助OpenQA.Selenium.Interactions.Actions类库中提供的方法, 实现起来还 ...

  2. Selenium WebDriver-通过ActionChains实现页面元素拖拽

    #encoding=utf-8 import unittest import time import chardet from selenium import webdriver class Visi ...

  3. Js元素拖拽功能实现

    Js元素拖拽功能实现 需要解决的问题 最近项目遇到了一个问题,就是用户某个操作需要弹出一个自定义的内容输入框,但是有个缺点,当浏览太大的时候没办法点击确认和取消按钮,应为这个弹出框是采用绝对定位的,取 ...

  4. VUE 元素拖拽、移动

    元素拖拽 作者:一粒尘土 时间:2019-10-30 使用范围:两个元素位置交换,移动元素到指定位置 涉及函数 属性 解释 draggable 是否允许元素进行拖拽 dragstart 拖拽开始触发的 ...

  5. WPF中元素拖拽的两个实例

    今天结合之前做过的一些拖拽的例子来对这个方面进行一些总结,这里主要用两个例子来说明在WPF中如何使用拖拽进行操作,元素拖拽是一个常见的操作,第一个拖拽的例子是将ListBox中的子元素拖拽到ListV ...

  6. vue全局自定义指令-元素拖拽

    小白我用的是vue-cli的全家桶,在标签中加入v-drap则实现元素拖拽, 全局指令我是写在main.js中 Vue.directive('drag', { inserted: function ( ...

  7. html5的元素拖拽

    今天学习了妙味课堂的课程: 在html5中有支持元素拖拽的一些属性和方法: 一些实例代码如下: <div id="div1"></div> <ul&g ...

  8. selenium学习-拖拽页面元素

    一.ActionChains包 模拟鼠标的操作要首先引入ActionChains的包 from selenium.webdriver.common.action_chains import Actio ...

  9. IE8利用setCapture和releaseCapture解决iframe的拖拽事件

    最近有个需求须要实现左右拖拽功能,页面右边是个iframe页面,在chrome测试通过之后,发现在ie8上面效果不是很理想,最后查找资料得知可以使用ie自带的setCapture和releaseCap ...

  10. jQuery网页元素拖拽插件

    效果说明:配合已有CSS样式,载入插件后,网页元素可以随意在窗口内拖拽,设置了原位置半透明和拖拽半透明的效果选项,可根据需要选择.另外,当页面上有多个可拖拽元素时,可以载入另外一个用于设置z-inde ...

随机推荐

  1. Docker容器 获取宿主机CPU信息等或重启网卡命令操作介绍

    一.作用场景及知识点 1. 使用场景(SSH方式除外): A. 运行在Docker容器里面的程序,怎么采集宿主机的CPU.内存.磁盘等信息: B. 容器内更改宿主机的网卡信息,怎么操作宿主机执行命令: ...

  2. element ui 分页

    修改选中页码的样式: .el-pager .active{ color:red !important;//选中 } .el-pager .number:hover{ color:red !import ...

  3. elk安装(简)

    1.到官网下载对应的版本注意最好使用版本相同的3个软件 elasticsearch-6.8.7.rpm kibana-6.8.7-x86_64.rpm logstash-6.8.7.rpm 我这里使用 ...

  4. URL Scheme获取

    支付宝链接或小程序获取URL Scheme 小程序(以行程卡小程序为例): URL解码https://c.runoob.com/front-end/695/ JS网址解码https://jsrun.n ...

  5. java通信

    RPC:同步 http webservice RMI:同步 RMI 是面向对象方式的 Java RPC . 类要extends java.rmi.Remote接口 JMS:异步 需要有消息队列 act ...

  6. 记一次mybatis中like 不执行sql的问题,单引号 与双引号的坑

    使用环境: springboot 2.0.4 mybatis-spring:1.3.2 错误也是比较蛋疼:  不报错,但是查询出来的结果不对. 原错误sql 示意:  select  * from  ...

  7. js本地时钟

    js本地时钟,如上图所示,秒是跳动的 1 // 本地时钟 2 function clockon() { 3 var now = new Date(); 4 var year = now.getFull ...

  8. 作业三:CART回归树

    作业三:CART回归树 20大数据三班 博客链接 学号 201613336 问题一: 表1为拖欠贷款人员训练样本数据集,使用CART算法基于该表数据构造决策树模型,并使用表2中测试样本集确定剪枝后的最 ...

  9. 【python】python,PyQt5以及Qt designer的使用_做界面(用vscode)

    1.PyQt5和Qt designer准备 win+r       cmd       输入以下 python -m pip install -i http://pypi.douban.com/sim ...

  10. 项目实训 DAY8

    功能页面开发完毕,实现了两种工具(d3.js/echarts.js)的可视化效果,并与前端整合完毕. 项目实训步入尾声,最后的几(一)天大概就是完善最后的工作,准备答辩.