当动画发生时,Selenium FirefoxDriver点击了错误的链接

Selenium FirefoxDriver clicks on wrong link when animations occur

本文关键字:错误 链接 FirefoxDriver Selenium 动画      更新时间:2023-09-26

我正在使用Selenium 2.35,在尝试点击firefox中的一个元素时出现了一个不可预测的错误,如下所示:

new Actions(driver).moveToElement(element).click().perform();

我所定位的元素是<span>元素与一个点击事件相关联。我遇到的问题是,当Firefox尝试点击该元素时,偶尔会错过并点击一个完全不同的元素。如果我使用调试器浏览代码,问题永远不会发生,这让我相信FirefoxDriver只是在浏览器上点击了错误的位置,这与时间问题有关。存在动态加载的<div>在我的页面上,使我想要点击的元素在我找到它并发送.click()命令之前下移。我相信这就是我问题的根源。我可以放一个Thread.sleep(500)来确保它有足够的时间来完成动画和插入动态div,但这对我来说似乎很草率。有没有办法告诉我的FirefoxDriver,等到屏幕上的元素移动完成后,它才能尝试发送.click()事件?

此外,我尝试只发送元素.click(),但似乎失败的次数更多。

更新(9/15/13):

在@MrTi评论的帮助下,我得出的解决方案如下:

private void jsClickOnElementById(String id)
{
    WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id(id)));
    JavascriptExecutor js = (JavascriptExecutor)driver;
    StringBuilder sb = new StringBuilder();
    sb.append("var x = $('#" + id + "');");
    sb.append("x.click();");
    js.executeScript(sb.toString());
}

为了确保元素确实在页面上,我添加了最初的"等待"调用,然后使用JavascriptExecutor运行一些jquery并单击页面上的元素。这似乎对我的案子很有效。如果有人能帮助解决这个解决方案的一些缺点,他们将不胜感激,因为我对JavascriptExecutor类还很陌生。

除了确保页面使用ExpectedConditions实际可见外,还可以通过处理页面上的动画(转换)来解决这种情况。

可以禁用页面上的所有动画,直到页面刷新,方法是执行:

(JavascriptExecutor)driver.executeScript("$('body').append('<style> * {transition: none!important;}</style>')")

此外,如果你知道获得动画的特定元素,你可以检查它是否已设置动画(JQuery动画选择器):

(Boolean)((JavascriptExecutor)driver).executeScript("return $("#ELEMENT_ID").is(":animated")")

如果特定元素未知,您可以确定是否所有动画都已完成:

(Boolean)((JavascriptExecutor)driver).executeScript("return $(":animated").length == 0 ")

遗憾的是,在2018年(五年后),我可以确认selenium中的element.click()并不总是点击正确的元素。我仍然需要使用JavascriptExecutor来执行jquery,以便通过jquery $(selector).click()按ID点击元素,从而自信地点击该元素。

不仅仅是因为滚动、动画或屏幕外的原因找不到元素,Selenium对Marionette内部DOM树的包装似乎与firefox的geckodriver不同步,因为动态加载的元素(在本例中是表行)

我相信发生的事情是动态加载使选择器选择了其他东西。如果您发布HTML(尤其是在动态加载之前/之后),这将对编写更好的选择器非常有帮助。

但是,有几种方法可以等待加载完成。

第一个等待直到(Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")返回true。这将等待页面上的所有JQuery完成(这可能是导致动态加载的原因)。这是有用的,但我建议等待其他东西。

第二种选择是等待,直到出现动态加载的元素:

wait.until(ExpectedConditions.presenceOfElementSelectedBy(...selector...));

我喜欢这种方法,因为它会等你需要的时间,而且不会再等了。

最后一个选择是编写一个选择器,它将始终选择元素,即使其他事情正在进行。这可能是你的最佳选择,但你也可能遇到StaleElementReferenceExceptions