PageFactory中的StaleElementReference异常

use*_*679 10 selenium pageobjects selenium-webdriver page-factory staleelementreferenceexception

我正在尝试学习PageFactory模型.我理解这样一个事实,当我们这样做时initElements,WebElements就位于其中.比如说,我点击了一个webelement,因此DOM中的其他一个元素发生了变化.现在,显然我会在StaleElementReferenceException这里得到一个.我该如何解决这个问题?

我是否应该再次发现特定的WebElement知道DOM中的WebElement属性可能发生了变化?还是有另一种方法来处理这个问题?

Deb*_*anB 13

StaleElementReferenceException

StaleElementReferenceException扩展了WebDriverException,并指示该元素的先前引用现在已过时且该元素引用不再出现在页面的DOM上.


常见原因

  • 面临的常见原因StaleElementReferenceException如下:
    • 该元素已被完全删除.
    • 该元素不再附加到DOM.
    • 该元素所属的网页已刷新.
    • (previous)元素已被JavaScriptAjaxCall删除,并被具有相同ID或其他属性的(new)元素替换.
  • 解决方案:如果(旧)元素已被新的相同元素替换,则简单的策略是使用findElement()findElements再次查找元素.

回答你的疑问

  1. 当我们执行initElements时,WebElements位于:当您调用initElements()method时,该页面的所有WebElements都将被初始化.例如,

    LoginPageNew login_page = PageFactory.initElements(driver, LoginPageNew.class);
    
    Run Code Online (Sandbox Code Playgroud)

    这行代码将初始化在自动化脚本调用时随时随地定义的所有静态WebElementsLoginPageNew.class.

  2. 我点击了一个webelement,因此DOM中的其他一个元素发生了变化:这几乎是可能的.

    • 举个例子,一般调用click()上的<input>标签将不会触发任何的任何变化WebElementsHTML DOM.
    • 凡为调用click()上一个<button>标签或<a>标签可调用的JavaScript阿贾克斯这inturn可以删除一个元素,或者可以通过一个(新的)元素用相同的替换(以前的)元素ID或其他属性.

结论

因此,如果WebDriver抛出StaleElementReferenceException,这意味着即使元素仍然存在,引用也会丢失.我们应该丢弃当前的引用,并在它附加到DOM时再次找到WebElement来替换它.这意味着您必须再次通过initElements()方法重新初始化该类,该方法将重新初始化该页面中定义的所有WebElements.


如果旧元素已被新的相同元素替换,则简单的策略是调用StaleElementReferenceExceptionID再次查找元素.


参考

以下是此讨论的参考:

  • 实际上,没有必要重新初始化您的页面类.再次搜索特定元素就足够了. (2认同)
  • 这是一个非常糟糕的答案,它导致您走上错误的道路,同时似乎解决了问题。如果您没有使用@CachLookup 注释,则不需要重新初始化该类,您只需再次使用 WebElement,将 WebElement 绑定到 DOM 中的元素的 Java 代理类将处理再次查找该元素. 重新初始化然后再次使用 WebElement 似乎有效,但这不是因为您重新初始化了类,而是因为您再次搜索了该元素。 (2认同)

小智 0

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(); 
    } 
  }); 
}
Run Code Online (Sandbox Code Playgroud)