Java Selenium stale元素引用,使用AjaxLocatorFactory
我有一个超级类Java Selenium stale元素引用,使用AjaxLocatorFactory,java,selenium,automated-tests,Java,Selenium,Automated Tests,我有一个超级类组件,在这个类中我存储了访问附加到组件的元素的常用方法 在组件构造函数中,我使用pagefactory初始化元素 PageFactory.initElements(new AjaxElementLocatorFactory(root,10), this); 据我所知,只要元素由@FindBy注释,这将自动保持元素引用的新鲜 我有一个专门的组件,名为SearchResultRow,它扩展了组件 在这个组件中,我拥有与搜索结果中的一行相关的所有WebElements 我想做的是得到第
组件
,在这个类中我存储了访问附加到组件的元素的常用方法
在组件
构造函数中,我使用pagefactory初始化元素
PageFactory.initElements(new AjaxElementLocatorFactory(root,10), this);
据我所知,只要元素由@FindBy注释,这将自动保持元素引用的新鲜
我有一个专门的组件
,名为SearchResultRow
,它扩展了组件
在这个组件中,我拥有与搜索结果中的一行相关的所有WebElements
我想做的是得到第一个搜索结果并点击它。这是我的代码
public void clickOnFirstResult() {
WebElement firstUser = wait.until(ExpectedConditions.elementToBeClickable(searchResultRoot.findElement(By.cssSelector("tbody > tr:nth-child(1)"))));
new SearchResultRow(firstUser).clickOn(SearchModel.NAME);
}
在这里,我等待元素变得可点击,因为@FindBy注释没有涵盖它是一个动态元素
SearchModel.NAME是指在SearchResultRow组件中由@FindBy注释的WebElement。然而,这种方法有时会产生10-15%的误差
陈旧元素引用:元素未附加到页面文档
这是由动态DOM引起的。
wait.until(ExpectedConditions.element可禁用(searchResultRoot.findElement(由.cssSelector(“tbody>tr:nth child(1)”)))代码>在找到元素并可单击时结束。但是,这是在DOM构建过程中发生的,因此当您尝试单击此元素时,它可能会消失/更改,从而使您引用的元素不再存在。
处理动态DOM页面最简单的方法是,每次重新加载/重建DOM/页面时,都要留出足够的延迟时间,然后再处理它的元素。
你已经问过类似的问题,我已经回答过了。根本原因
Stale element reference是指在页面刷新之前获得但试图使用的web元素(即在所述刷新之后调用click()
方法)
解决方案
等等。。。。等待页面重新加载的最佳方式是什么?一种方法是使用隐式等待。一种非常常见的隐式等待时间的方法:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
在SeleniumJava中就是这样做的,但是对于您使用的任何版本的Selenium,都应该有一个等效的方法。现在的问题是,这有什么用?这是告诉web驱动程序在尝试获取web元素之前等待给定时间的方法。当设置了隐式等待
时间时,它将在测试会话期间保持设置。因此,这通常是在任何测试开始执行之前的一开始就完成的。更具体地说,您应该在获得web驱动程序实例后立即执行此操作
也就是说,这还不够。例如,如果组件在初始加载页面后变得陈旧,该怎么办?为此,您应该使用ExpectedConditions
类并设置显式等待某个条件发生:
WebDriverWait wait = new WebDriverWait(driver, 10); // timeout of 10 seconds and polling the default value of 500 ms, or...
WebDriverWait wait = new WebDriverWait(driver, 10, 100); // timeout of 10 seconds and polling every 100 ms
然后使用wait
object设置预期条件并获取所需的web元素
WebElement element = wait.until(...);
您需要将适当的ExpectedConditions
传递给上述方法。避免陈腐的常用方法:
WebElement element = wait.until(ExpectedConditions.elementSelectionStateToBe(...));
WebElement element = wait.until(ExpectedConditions.refreshed(...));
最后,在与元素交互之前,您将检查元素的状态。例如:
WebElement newElement = wait.until(ExpectedConditions.elementToBeClickable(element));
newElement.click();
在这种情况下,element
和newElement
是同一个对象,因此只需使用wait.until(ExpectedConditions.elementtobelickable(element))在调用元素之前,code>应该足够了。单击()
。至此,您已经确定该元素不是过时的,并且是可见的和已启用的;因此,可以安全地单击(例如)。“处理动态DOM页面的最简单方法是每次重新加载/重建DOM/页面时,都要提供足够的延迟时间,并且只有在这之后才能处理其元素。”这方面的好做法是什么?这就是我试图通过使用AjaxElementLocatorFactory来实现的,我建议您使用循环。尝试单击该元素。如果成功-确定,则退出循环,如果失败并引发异常,请在catch部分增加一些计数器,稍等片刻,然后重试。这是否回答了您的问题@Eliyahu使用这个答案中的方法看起来真的很糟糕。我的意思是,他们基本上是在使用变通方法。没有,但这是7年前的事了。当然,在我们的无片硒测试之旅中,我们肯定已经走得更远了。好的,如果你有更好的方法,欢迎你在那里和其他类似的帖子上回答。这会给你很多投票权。我不是已经在用WebElement firstUser=wait.until(ExpectedConditions.elementtobelickable(searchResultRoot.findelelement)(By.cssSelector(“tbody>tr:nth child(1)”))代码>@santino98这与你在做什么无关。这是你什么时候做这件事的问题。如果在页面刷新之前设置了条件,则会遇到过时的元素问题。记住,stale的意思是“旧的”。这意味着DOM中有一个比您拥有的元素更新的元素。这是一个很好的观点。我想可能发生的是angularJS在我等待病情的时候把DOM搞乱了。“条件是正确的,但角度不确定。”@santino98不知道你的具体情况,这将是我的猜测。我也经历过类似的问题。基本方法是1)设置页面加载完成的默认时间(隐式等待),以阻止获取元素,直到该时间过去;2)使用ExpectedConditions
设置与web元素交互之前要等待的特定条件;以及3)与元素交互。这将适用于80%-90%的情况,对于其余情况,您必须稍微调整此方法。@santino98在某些情况下,我所做的一件事是捕获异常(即stale元素),并在catch块上重试该过程。然后,仅在重试后失败。