Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Selenium stale元素引用,使用AjaxLocatorFactory_Java_Selenium_Automated Tests - Fatal编程技术网

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块上重试该过程。然后,仅在重试后失败。