我想学习PageFactory模型。 我明白了一个事实,当我们做一个initElements
,该WebElements所在。 比方说,我点击一个webelement因为其中有在DOM其他webelements的一个变化。 现在,很明显,我会得到一个StaleElementReferenceException
这里。 我将如何解决这个问题?
我应该发现,特定WebElement再次知道的事实,有可能在DOM的WebElement的性质发生变化? 或者说还有什么别的办法来处理这个?
StaleElementReferenceException
StaleElementReferenceException延伸WebDriverException并指示该元素的前一个参考已经陈旧和元素引用不再出现在页面的DOM。
常见原因
- 面对背后的常见原因
StaleElementReferenceException
如下: - 该元素已经被全部删除。
- 的元件不再连接到DOM。
- 该网页上的元素是已被刷新的一部分。
- 的(上次的)元件已经由JavaScript,或者AjaxCall的删除,并通过用相同的(新的)元素取代
ID
或其他属性。
- 解决方法:如果(旧)元素已被替换为新的相同的一个,简单的策略是使用
findElement()
或findElements
再次看出来的元素。
回答你的疑问
当我们做一个initElements,该WebElements位于 :当你调用initElements()
方法,该页面的所有WebElements将得到初始化。 例如,
LoginPageNew login_page = PageFactory.initElements(driver, LoginPageNew.class);
这行代码将初始化的范围内定义的所有静态WebElements LoginPageNew.class
无论何时何地它是从你的自动化脚本调用。
我点击一个webelement因为其中有在DOM其他webelements的一个变化 :这是非常可能的。
- 作为一个例子,在一般调用
click()
上的<input>
标签不会触发的任何对的WebElements的任何改变的HTML DOM 。 - 其中作为调用
click()
上的<button>
标签或<a>
标签可以呼叫JavaScript或Ajax的哪个inturn可以删除一个元素,或可通过一个(新)元件用相同的替换(先前)元素ID
或其他属性。
结论
所以,如果webdriver的抛出一个StaleElementReferenceException,暗示即使元素依然存在,基准丢失。 我们应该抛弃目前的参考,我们必须通过再次定位WebElement当它被附加到DOM更换。 这意味着你必须再次重新初始化通过类initElements()
方法,它inturn重新初始化在页面中定义的所有WebElements。
解
如果旧元素已被替换成新的一样一个,简单的策略是调用WebDriverWait inconjunction与ExpectedConditions看出来的元素。
你可以找到相关的详细讨论:
- 如何添加明确的等待中PageFactory在PageObjectModel?
参考
以下是本次讨论的参考:
- 过时的元素引用异常
- 类StaleElementReferenceException
- 硒:如何判断RemoteWebDriver.findElements(通过)可以抛出StaleElementReferenceException呢?
这是一个已知的问题PageFactory实施。
如果你运气不好足够的元素之间的即时成为过时的元素被发现,然后元素被点击时,你会得到这个错误。 不幸的是,PageFactory代码不会尝试再次找到该元素,如果它已经成为陈旧,它抛出一个异常。
我想这个分类与PageFactory一个bug,它应该自动重新找到元素,如果它曾经变得陈旧(除非使用@CacheLookup注释)。
召回initElements的建议是不会解决任何事情,你只需要一次初始化的元素,因为结合Java代理类有问题的元素。 该网页工厂实现应该删除StaleElementReferenceExceptions的可能性(所以为什么这是一个bug)
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();
}
});
}