14

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

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

4

3 回答 3

17

陈旧元素引用异常

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


常见原因

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

回答您的疑问

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

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

    这行代码将初始化在您的自动化脚本中无论何时何地调用它的范围内定义的所有静态WebElement 。LoginPageNew.class

  2. 我单击一个 web 元素,因此 DOM 中的其他 web 元素之一发生了变化:这很有可能。

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

结论

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


解决方案

如果旧元素已被新的相同元素替换,简单的策略是调用WebDriverWaitExpectedConditions结合以查找该元素。

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


参考

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

于 2017-06-30T11:00:30.017 回答
3

这是 PageFactory 实现的一个已知问题。

如果您很不幸,在找到元素和单击该元素之间的瞬间元素变得陈旧,您将收到此错误。不幸的是,如果 PageFactory 代码已经过时并抛出异常,它不会尝试再次找到该元素。

我会将其归类为 PageFactory 的错误,如果它变得陈旧,它应该自动重新查找元素(除非使用 @CacheLookup 注释)。

召回 initElements 的建议不会解决任何问题,您只需初始化元素一次,因为这会将 Java 代理类绑定到相关元素。页面工厂实现应该消除 StaleElementReferenceExceptions 的可能性(因此这是一个错误)

于 2019-03-09T19:46:48.587 回答
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(); 
    } 
  }); 
}
于 2017-06-30T05:07:48.410 回答