故事:
在StackOverflow上,我看到用户报告说他们不能通过selenium WebDriver“click”命令单击元素,而可以通过执行脚本使用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());
问题是:
为什么点击“Via JavaScript”可以工作,而常规的WebDriver点击却不行?这到底是什么时候发生的,这个变通方法的缺点是什么(如果有的话)?
我个人使用了此变通方法,但没有完全理解为什么必须这样做以及它会导致什么问题。
与当前接受的答案相反,当涉及到让WebDriver点击和在JavaScript中点击之间的区别时,PhantomJS并没有什么特别之处。
这两种方法之间的本质区别是所有浏览器所共有的,可以非常简单地解释:
>
WebDriver:当WebDriver执行单击操作时,它会尽可能地模拟真实用户使用浏览器时发生的情况。假设您有一个元素A,它是一个表示“click Me”的按钮,还有一个元素B,它是一个div
元素,它是透明的,但是它的尺寸和zindex
被设置成完全覆盖A。然后您告诉WebDriver单击A。WebDriver将模拟单击,以便B首先接收到单击。为什么?因为B覆盖A,如果用户试图单击A,那么B将首先获得事件。A最终是否获得click事件取决于B如何处理该事件。无论如何,这种情况下WebDriver的行为与实际用户尝试单击a时的行为是相同的。
JavaScript:现在,假设您使用JavaScript来执行a.click()
。这种单击方法不会重现用户尝试单击A时真正发生的情况。JavaScript将click
事件直接发送给A,而B将不会获得任何事件。
正如我上面提到的,WebDriver将尽可能地模拟真实用户使用浏览器时发生的情况。事实是DOM可以包含用户无法与之交互的元素,而WebDriver不允许您单击这些元素。除了我提到的重叠情况外,这还意味着不能点击不可见的元素。我在Stack Overflow questions中看到的一个常见情况是,有人试图与DOM中已经存在的GUI元素进行交互,但只有在其他元素被操纵时才变得可见。下拉菜单有时会出现这种情况:您必须首先单击下拉菜单上的按钮,然后才能选择菜单项。如果有人试图在菜单可见之前单击菜单项,WebDriver会犹豫不决,并表示无法操纵该元素。如果该人员随后尝试使用JavaScript来完成,它将工作,因为事件直接传递到元素,而不考虑可见性。
如果您正在使用Selenium来测试应用程序,我对这个问题的回答是“几乎从来没有”。大体上,Selenium测试应该重现用户对浏览器的操作。以下拉菜单为例:一个测试应该先点击打开下拉菜单的按钮,然后点击菜单项。如果由于按钮不可见而导致GUI出现问题,或者按钮无法显示菜单项,或者类似的情况,那么您的测试将失败,您将检测到错误。如果您使用JavaScript来点击周围,您将无法通过自动化测试来检测这些bug。
我说“几乎从来没有”是因为在使用JavaScript有意义的地方可能会有例外。不过,它们应该很少见。
如果您正在使用Selenium刮取站点,那么尝试再现用户行为就不是那么关键了。因此使用JavaScript绕过GUI不是一个问题。