4

我正在使用 Selenium 2.35 并在尝试单击 Firefox 中的元素时遇到不可预测的错误,如下所示:

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

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

另外,我试图只发送 element.click() 但这似乎更频繁地失败。

更新(2013 年 9 月 5 日):

我在@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 类相当陌生。

4

3 回答 3

3

除了使用 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 ")
于 2014-11-27T14:00:38.987 回答
2

可悲的是,在 2018 年(五年后),我可以确认 selenium 中的 element.click() 并不总是单击正确的元素。我仍然需要使用 JavascriptExecutor 对 jquery 进行封装,以通过 ID 来单击一个元素,jquery $(selector).click()以便自信地点击该元素。

不仅仅是因为滚动、动画或屏幕外它找不到元素,它似乎 Selenium 的 Marionette 内部 DOM 树的包装器与 firefox 的 geckodriver 不同步,以某种方式用于动态加载的元素(在本例中为表格行)

于 2018-09-23T01:17:34.240 回答
1

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

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

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

第二种选择是等到存在动态加载的元素:

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

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

最后的选择是编写一个选择器,它总是选择元素,即使其他事情正在发生。这可能是您最好的选择,但您也可能会遇到StaleElementReferenceExceptions.

于 2013-09-04T20:51:53.803 回答