WebDriver click() 与 JavaScript click()

2024-12-24 08:56:00
admin
原创
89
摘要:问题描述:故事:在 StackOverflow 上,我看到用户报告说他们无法通过 selenium WebDriver 的“单击”命令单击元素,但可以通过执行脚本使用 JavaScript 单击来解决这个问题。Python 中的示例:element = driver.find_element_by_id(&q...

问题描述:

故事:

在 StackOverflow 上,我看到用户报告说他们无法通过 selenium WebDriver 的“单击”命令单击元素,但可以通过执行脚本使用 JavaScript 单击来解决这个问题。

Python 中的示例:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

WebDriverJS/Protractor 中的示例:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

问题:

为什么单击“通过 JavaScript”有效,而单击常规 WebDriver 无效?这种情况究竟是什么时候发生的,这种解决方法的缺点是什么(如果有的话)?

我个人使用了这个解决方法,但没有完全理解为什么必须这样做以及它会导致什么问题。


解决方案 1:

与当前接受的答案相反,当谈到让 WebDriver 执行点击和使用 JavaScript 执行点击之间的区别时,PhantomJS 并没有什么特别之处。

区别

这两种方法之间的本质区别对于所有浏览器来说都是相同的,并且可以很简单地解释:

  • WebDriver:当 WebDriver 执行点击时,它会尽可能地模拟真实用户使用浏览器时发生的情况。假设您有一个元素 A,它是一个按钮,上面写着“点击我”,还有一个元素 B,它是一个div透明的元素,但其尺寸和zIndex设置使其完全覆盖 A。然后您告诉 WebDriver 单击 A。WebDriver 将模拟点击,以便 B首先收到点击。为什么?因为 B 覆盖了 A,如果用户尝试点击 A,那么 B 将首先收到事件。A 最终是否会收到点击事件取决于 B 如何处理该事件。无论如何,在这种情况下 WebDriver 的行为与真实用户尝试点击 A 时的行为相同。

  • JavaScript: 现在,假设你使用 JavaScript 来做A.click()这种点击方式并不能重现用户尝试点击 A 时真正发生的情况。JavaScript直接将事件发送click给 A,而 B 不会收到任何事件。

为什么 JavaScript 单击有效而 WebDriver 单击无效?

正如我上面提到的,WebDriver 将尽可能地模拟真实用户使用浏览器时发生的情况。事实上,DOM 可能包含用户无法与之交互的元素,而 WebDriver 不允许您单击这些元素。除了我提到的重叠情况之外,这还意味着不可见元素无法被单击。我在 Stack Overflow 问题中看到的一个常见情况是,有人试图与 DOM 中已经存在的 GUI 元素进行交互,但只有当其他元素被操作后才可见。这有时会发生在下拉菜单中:您必须先单击按钮以调出下拉菜单,然后才能选择菜单项。如果有人在菜单可见之前尝试单击菜单项,WebDriver 会犹豫不决并说该元素无法被操作。如果此人随后尝试使用 JavaScript 执行此操作,它将起作用,因为事件直接传递给元素,而与可见性无关。

何时应使用 JavaScript 进行点击?

如果您使用 Selenium测试应用程序,我对这个问题的回答是“几乎从不”。总的来说,您的 Selenium 测试应该重现用户使用浏览器的操作。以下拉菜单为例:测试应该首先单击弹出下拉菜单的按钮,然后单击菜单项。如果 GUI 出现问题(因为按钮不可见,或者按钮无法显示菜单项,或类似情况),那么您的测试将失败,您将检测到错误。如果您使用 JavaScript 进行点击,您将无法通过自动化测试检测到这些错误。

我说“几乎从不”是因为可能存在使用 JavaScript 的例外情况。不过,这种情况应该非常罕见。

如果您使用 Selenium 来抓取网站数据,那么尝试重现用户行为就不那么重要了。因此,使用 JavaScript 绕过 GUI 并不是什么大问题。

解决方案 2:

驱动程序执行的点击会尝试尽可能接近地模拟真实用户的行为,同时 JavaScriptHTMLElement.click()会执行事件的默认操作click,即使元素不可交互。

不同之处在于:

  • 驱动程序通过将元素滚动到视图中来确保元素可见,并检查元素是否可交互

驱动程序将引发错误:

+ 当点击坐标顶部的元素不是目标元素或后代时
+ 当元素没有正尺寸或完全透明时
+ 当元素为禁用输入或按钮时(属性/属性`disabled`为`true`)
+ 当元素禁用鼠标指针时(CSS`pointer-events`为`none`)  

如果元素被禁用, JavaScriptHTMLElement.click()将始终执行默认操作,或者最多会默默失败。

  • 如果元素可聚焦,则驱动程序将元素置于焦点之中。

JavaScript 则HTMLElement.click()不会。

  • 预计驱动程序将像真实用户一样发出所有事件(mousemove、mousedown、mouseup、click 等)。

JavaScriptHTMLElement.click()仅发出click事件。页面可能会依赖这些额外事件,如果不发出这些事件,页面的行为可能会有所不同。

这些是驱动程序在 Chrome 点击时发出的事件:

mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }

这是通过 JavaScript 注入发出的事件:

click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
  • JavaScript 发出的事件.click() 不受信任,可能无法调用默认操作:

https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted

https://googlechrome.github.io/samples/event-istrusted/index.html

请注意,某些驱动程序仍在生成不受信任的事件。PhantomJS 2.1 版就是这种情况。

  • JavaScript 发出的事件.click() 没有点击的坐标

属性clientX, clientY, screenX, screenY, layerX, layerY设置为0。页面可能依赖它们,并且可能表现不同。

使用 JavaScript.click()抓取一些数据可能没问题,但这不是在测试环境中。它违背了测试的目的,因为它没有模拟用户的行为。因此,如果驱动程序的点击失败,那么真实用户很可能也会在相同条件下无法执行相同的点击。

当我们期望成功点击元素时,是什么原因导致驱动程序无法点击元素?

  • 由于延迟或过渡效果,目标元素尚不可见/不可交互。

一些例子:

https://developer.mozilla.org/fr/docs/Web(下拉导航菜单)
http://materializecss.com/side-nav.html(下拉侧边栏)

解决方法:

添加一个服务员来等待可见性,最小尺寸或稳定位置:

// wait visible
browser.wait(ExpectedConditions.visibilityOf(elem), 5000);

// wait visible and not disabled
browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);

// wait for minimum width
browser.wait(function minimumWidth() {
    return elem.getSize().then(size => size.width > 50);
}, 5000);

重试点击直至成功:

browser.wait(function clickSuccessful() {
    return elem.click().then(() => true, (ex) => false);
}, 5000);

添加与动画/过渡持续时间相匹配的延迟:

browser.sleep(250);
  • 一旦滚动到视图中,目标元素就会被浮动元素覆盖:

驱动程序会自动将元素滚动到视图中以使其可见。如果页面包含浮动/粘性元素(菜单、广告、页脚、通知、cookie 政策......),该元素最终可能会被覆盖,并且不再可见/可交互。

例如:https://twitter.com/?lang=en

解决方法:

将窗口尺寸设置为较大的尺寸以避免滚动或浮动元素。

将鼠标移到具有负偏移的元素上Y,然后单击它:

  browser.actions()
     .mouseMove(elem, {x: 0, y: -250})
     .click()
     .perform();

在点击之前将元素滚动到窗口的中心:

browser.executeScript(function scrollCenter(elem) {
  var win = elem.ownerDocument.defaultView || window,
    box = elem.getBoundingClientRect(),
    dy = box.top - (win.innerHeight - box.height) / 2;
  win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
}, element);

element.click();

如果无法避免,则隐藏浮动元素:

browser.executeScript(function scrollCenter(elem) {
  elem.style.display = 'none';
}, element);

解决方案 3:

注意:我们将“点击”称为最终用户点击。“js 点击”是通过 JS 点击

为什么单击“通过 JavaScript”有效,而单击常规 WebDriver 无效?

有两种情况会导致这种情况发生:

一、如果你使用 PhamtomJS

那么这是最常见的行为PhantomJS。有些元素有时不可点击,例如<div>。这是因为PhantomJS最初是为了模拟浏览器引擎(如初始 HTML + CSS -> 计算 CSS -> 渲染)而制作的。但它并不意味着以最终用户的方式进行交互(查看、点击、拖动)。因此PhamtomJS仅部分支持最终用户的交互。

JS CLICK 为何有效?至于任何一种点击,它们都是平均点击。它就像一把有1 个枪管2 个扳机的枪。一个来自视口,一个来自 JS。由于PhamtomJSJS 点击可以很好地模拟浏览器引擎,因此它应该可以完美地工作。

II. “点击”事件处理程序在错误的时间段内进行绑定。

例如,我们得到了一个<div>

  • -> 我们做了一些计算

  • -> 然后我们将点击事件绑定到<div>

  • -> 加上一些角度错误编码(例如没有正确处理范围的循环)

我们可能最终会得到相同的结果。单击不起作用,因为 WebdriverJS 在没有单击事件处理程序的情况下尝试单击元素。

为什么 JS CLICK 有效? JS CLICK 就像直接将 JS 注入浏览器一样。可能有两种方式,

首先是通过 devtools 控制台(是的,WebdriverJS 确实与 devtools 的控制台通信)。

第二种是直接在 HTML 中注入<script>标签。

对于每个浏览器,行为都会有所不同。但无论如何,这些方法比单击按钮更复杂。单击是使用已经存在的内容(最终用户单击),js单击是通过后门。

而对于 js 来说,点击会表现为一个异步任务。这又涉及到一个比较复杂的话题‘浏览器异步任务和 CPU 任务调度’(很久以前看过,现在找不到了)。简单来说,这主要是因为 js 点击需要等待一个CPU 任务调度周期,绑定点击事件后,运行速度会慢一些。
(当你发现元素有时可点击,有时不可点击时,你就知道这种情况了。)

这究竟是什么时候发生的,以及这种解决方法的缺点是什么(如果有的话)?

=> 如上所述,两者都意味着一个目的,但关于使用哪个入口:

  • 点击:正在使用浏览器默认提供的。

  • JS 点击:正在通过后门。

=> 至于性能,很难说,因为它依赖于浏览器。但一般来说:

  • 单击:并不代表速度更快,只是在CPU执行任务的调度列表中签署更高的位置。

  • JS点击:并不代表速度变慢,只是排在了CPU任务调度列表的最后位置。

=> 缺点:

  • 单击:除了使用 PhamtomJS 之外,似乎没有任何缺点。

  • JS 点击:对健康非常不利。您可能会意外点击视图中不存在的内容。使用此功能时,请确保元素存在且可供最终用户查看和点击。

PS如果您正在寻找解决方案。

  • 使用 PhantomJS?我建议改用 Chrome headless。是的,您可以在 Ubuntu 上设置 Chrome headless。它的运行方式与 Chrome 一样,但它没有视图,并且错误比 PhantomJS 少。

  • 不使用 PhamtomJS 但仍有问题?我建议使用 Protractor 的 ExpectedCondition browser.wait()(查看此处了解更多信息)

(我想写得简短,但结果很糟糕。任何与理论相关的东西都很难解释......)

解决方案 4:

感谢您的详细解释,我遇到了同样的问题,您的解释帮助我解决了这个问题。

button = driver.wait.until(EC.presence_of_element_located(
    (By.XPATH, "//div[@id='pagination-element']/nav[1]/span[3]/button[1]/span[1]/i[1]")
))
driver.execute_script("arguments[0].click();", button)

解决方案 5:

在此处输入图片描述

if (theElement.Enabled)
{
    if (!theElement.Selected)
    {
      var driver = (IJavaScriptExecutor)Driver;
      driver.ExecuteScript("arguments[0].click();", theElement); //ok

      //theElement.Click();//action performed on theElement, then pops exception   
     }
 }

我不同意我们“几乎永远不会”使用 JS 来模拟点击动作。

上面theElement.Click(),我们检查单选按钮,但随后会弹出异常,如上图所示。

其实这个Click之后并没有页面加载的动作,点击只是选中Radio按钮,不知道WebDriver为什么Click()会引发这个异常,有谁能解释一下为什么会发生这个异常吗?

我使用Webdriver 3.141.59和 IE 11 以及selenium-server-standalone-3.141.59.jar进行远程测试。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1120  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   75  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   66  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   76  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   70  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用