PageFactory 中的 StaleElementReference 异常



我正在尝试学习PageFactory模型。我理解这样一个事实,即当我们做一个initElements,Web元素被定位。例如,我单击一个 webelement,因此 DOM 中的其他 Web 元素之一发生了变化。现在,显然我会在这里得到一个StaleElementReferenceException。我将如何解决此问题?

我是否应该再次找到特定的WebElement,知道DOM中WebElement的属性可能会发生变化? 还是有另一种方法可以解决这个问题?

StaleElementReferenceException

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


常见原因

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

回答您的疑问

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

    LoginPageNew login_page = PageFactory.initElements(driver, LoginPageNew.class);
    

    无论何时何地从自动化脚本调用此代码,此代码行都将初始化LoginPageNew.class范围内定义的所有静态 WebElements

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

    • 例如,通常调用<input>标签上的click()不会触发HTML DOM上任何Web元素的任何更改。
    • <button>标签或<a>标签上调用click()可以调用JavaScriptAjax,后者反过来可能会删除元素或可以用具有相同ID或其他属性的(新(元素替换(以前的(元素。

结论

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


溶液

如果旧元素已替换为新的相同元素,则简单的策略是将WebDriverWait与ExpectConditions一起调用以查找该元素。

您可以在以下位置找到相关的详细讨论:

  • 如何在PageObjectModel的PageFactory中添加显式等待?

引用

以下是本次讨论的参考资料:

  • 过时元素引用异常
  • 类 StaleElementReferenceException
  • Selenium:如何判断 RemoteWebDriver.findElements(By( 是否可以抛出 StaleElementReferenceException?

这是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(); 
    } 
  }); 
}

相关内容

  • 没有找到相关文章

最新更新