我正在尝试学习PageFactory模型。我了解一个事实,当我们执行initElements
时,将定位WebElement。举例来说,我单击一个Web元素,因此DOM中的其他Web元素之一发生了变化。现在,显然我会在这里得到一个StaleElementReferenceException
。我该如何解决这个问题?
我应该再次知道特定的WebElement知道DOM中WebElement的属性可以更改的事实吗?还是有另一种方法来处理此问题?
[StaleElementReferenceException扩展WebDriverException,并指示元素的先前引用现在为stale,并且元素引用不再存在于页面的DOM上。
StaleElementReferenceException
的常见原因如下:ID
或其他属性的(新)元素替换。findElement()
或findElements
再次寻找该元素。[当我们执行initElements时,WebElements位于]:当您调用initElements()
方法时,该页面的所有WebElements将被初始化。例如,
LoginPageNew login_page = PageFactory.initElements(driver, LoginPageNew.class);
此代码行将随时随地从自动化脚本中调用LoginPageNew.class
范围内定义的所有静态WebElements初始化。
我单击一个Web元素,因此DOM中其他Web元素之一发生了变化:这几乎是可能的。
click()
标签上调用<input>
不会触发HTML DOM上任何WebElements的任何更改。 click()
标记或<button>
标记上调用<a>
的地方可能调用JavaScript或Ajax,这反过来可能会删除一个元素或可以用( (新)具有相同ID
或其他属性的元素。因此,如果WebDriver抛出StaleElementReferenceException,这意味着即使该元素仍然存在,该引用也会丢失。我们应该丢弃当前的引用,并在WebElement附加到DOM时再次定位它。这意味着您必须再次通过initElements()
方法重新初始化该类,从而重新初始化该页面中定义的所有WebElements。
如果旧的元素已替换为新的相同元素,简单的策略是调用WebDriverWait与ExpectedConditions联合以寻找该元素。
您可以在以下位置找到相关的详细讨论:
这里是此讨论的参考:
这是PageFactory实现的一个已知问题。
如果不幸的是,在找到的元素与被单击的元素之间的瞬间,该元素变得过时,则会出现此错误。不幸的是,如果PageFactory代码变得陈旧并引发异常,则它不会尝试再次查找该元素。
我将其归类为PageFactory的错误,如果该元素过时,它将自动重新查找该元素(除非使用@CacheLookup批注)。
撤回initElements的建议不会解决任何问题,您只需初始化一次元素,因为这会将Java代理类绑定到所讨论的元素。页面工厂实现应消除StaleElementReferenceExceptions的可能性(因此,这是一个错误)
Stale element exception
在两种情况下抛出
元素不再连接到DOM
。该元素已被完全删除。
发生这种情况时,您将代码包装在try catch block
中,然后可以根据需要循环并重试多次,直到成功为止。
public void waitForElementPresent(final By by, int timeout){
WebDriverWait wait = (WebDriverWait)new WebDriverWait(driver,timeout)
.ignoring(StaleElementReferenceException.class);
wait.until(new ExpectedCondition<Boolean>(){
@Override
public Boolean apply(WebDriver webDriver) {
WebElement element = webDriver.findElement(by);
return element != null && element.isDisplayed();
}
});
}