解决Selenium元素拖拽不生效Bug

前几天在使用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 seletoolsfrom seletools.actions import drag_and_dropsource = 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中提供任何暂时避开网络的方法并不是一个好主意。

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/801274.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外部模块介绍(七) 蓝牙HC05

HC05原理图 2. 蓝牙模块的调试 2.1 两种工作模式: HC-05蓝牙串口通讯模块具有两种工作模式:命令响应工作模式和自动连接工作模式。在自动连接工作模式下模块又可分为主(Master)、从(Slave)和回环(Loopback)三种工作角色。 当模块处于自动连接工作模式时,将自动根据事…

二叉树练习day.3

104.二叉树的最大深度 链接:. - 力扣(LeetCode) 题目描述: 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root…

pygame旋转直线,计算角色到墙距离

pygame怎么计算距离 在Pygame中,计算两点之间的距离可以使用几何公式。给定两点P1(x1, y1)和P2(x2, y2),距离D可以用以下公式计算: D √((x2 - x1) (y2 - y1)) 在Python中,你可以使用math库中的sqrt函数来计算平方根。以下是一…

34-5 CSRF漏洞 - CSRF分类

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 1)GET 类型 传参: 参数连接在URL后面 POC构造及执行流程: 构造URL,诱导受害者访问点击利用利用标签进行攻击: 构造虚假URL,在链接上添加payload抓包获取数据包,通过CSRF POC…

excel散点图怎么每个点添加名称

最终效果图: 添加图标元素->数据标签->其他数据标签选项 选择单元格中的值 手动拖动数据标签,调整到合适的位置。

C语言从入门到实战————编译和链接

目录 前言 1. 翻译环境和运行环境 2. 翻译环境 2.1 预处理(预编译) 2.2 编译 2.2.1 词法分析: 2.2.2 语法分析 2.2.3 语义分析 2.3 汇编 2.4 链接 3. 运行环境 前言 编译和链接是将C语言源代码转换成可执行文件的必经过程&a…

Java面试八股文(更新中)

Java面试八股文 1. 基础篇1.1 Java语言特点1.2 面向对象和面向过程的区别1.3 八种基本数据类型的大小,以及他们的封装类1.4 标识符的命名规则1.5 instanceof 关键字的作用 ************************************************************* 1. 基础篇 1.1 Java语言特…

【Java网络编程】计算机网络基础概念

就目前而言,多数网络编程的系列的文章都在围绕着计算机网络体系进行阐述,但其中太多理论概念,对于大部分开发者而言,用途甚微。因此,在本系列中则会以实际开发者的工作为核心,从Java程序员的角度出发&#…

测试自动化流程设计思路

a) 背景介绍 基于当前互联网敏捷开发的现状,手工人力测试已不足以满足当前快速的版本迭代;以下将介绍一种可实现的自动化设计与使用。 b) 当前版本迭代流程 研发同学从代码库master分支拉出新代码进行研发工作得开发开发完成之后提交到代码库测试同学介入…

ES入门十一:正排索引和倒排索引

索引本质上就是一种加快检索数据的存储结构,就像书本的目录一下。 为了更好的理解正排索引和倒排索引,我们借由一个 **唐诗宋词比赛,**这个比赛一共有两个项目: 给定诗词名称,背诵整首给诗词中几个词语,让…

构建第一个ArkTS用的资源分类与访问

应用开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。 应用资源:借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表…

男生穿什么裤子显腿长?男生显腿长裤子分享

现在市面上出现很多劣质而且不耐洗不耐穿的裤子,不但穿着体验感差,而且还可能会对皮肤有影响。为此作为一名穿搭博主,我专门做了这篇关于男生裤子的测评,希望大家能够通过一下的科普知识,对选择裤子有更详细的了解。 什…

CDN加速原理那些事

名词解释 CNAME记录(CNAME record) CNAME即别名( Canonical Name );可以用来把一个域名解析到另一个域名,当 DNS 系统在查询 CNAME 左面的名称的时候,都会转向 CNAME 右面的名称再进行查询,一直追踪到最后…

创建型模式--4.抽象工厂模式【弗兰奇一家】

1. 奔向大海 在海贼世界中,位于水之都的弗兰奇一家是由铁人弗兰奇所领导的以拆船为职业的家族,当然了他们的逆向工程做的也很好,会拆船必然会造船。船是海贼们出海所必备的海上交通工具,它由很多的零件组成,从宏观上看…

算法:完全背包问题dp

文章目录 一、完全背包问题的特征二、定义状态三、状态转移四、降维优化五、参考例题5.1、Acwing:3.完全背包问题5.2、Acwing:900. 整数划分 一、完全背包问题的特征 完全背包问题是动态规划中的一种经典问题,它的主要特征可以总结如下&…

[HackMyVM]靶场Flossy

难度:Medium kali:192.168.56.104 靶机:192.168.56.142 端口扫描 ┌──(root㉿kali2)-[~/Desktop] └─# nmap 192.168.56.142 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-01 21:01 CST Nmap scan report for 192.168.56.142 Host is up (0.00018s latency).…

聊聊Linux内核中内存模型

介绍 在Linux中二进制的程序从磁盘加载到内存,运行起来后用户态是使用pid来唯一标识进程,对于内核都是以task_struct表示。二进制程序中的数据段、代码段、堆都能提现在task_struct中。每一个进程都有自己的虚拟地址空间,虚拟地址空间包含几…

stack和queue的使用

前言 前面我们对string、vector、list做了介绍并对底层进行了实现!本期我们继续来介绍STL容器,stack和queue! 本期内容介绍 stack 常用接口的介绍 queue 常用接口的介绍 什么是stack? 这里的栈和我们C语言实现的数据结构的那个栈功能是一样…

leetcode代码记录(最长连续递增序列

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定…

如何查看当前python环境的安装路径

起因&#xff1a;在查看python安装路径时&#xff0c;由于环境变量未添加&#xff0c;导致直接用python无法查看&#xff0c;但是pip又可用。因此找到另外一种代替方法。 利用pip show 库 pip show numpy