【问题标题】:StaleElementReference Exception in PageFactoryPageFactory 中的 StaleElementReference 异常
【发布时间】:2017-12-03 22:42:32
【问题描述】:

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

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

【问题讨论】:

标签: selenium selenium-webdriver pageobjects page-factory staleelementreferenceexception


【解决方案1】:

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. 我点击了一个 web 元素,因此 DOM 中的其他 web 元素之一发生了变化:这很有可能。

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

结论

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


解决方案

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

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


参考文献

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

【讨论】:

  • 实际上,没有必要重新初始化您的页面类。再次搜索特定元素就足够了。
  • @BreaksSoftware 我认为您在回复时缺少 PageFactory 的概念。整个答案基于我提到的 URL 中的概念,仅结合 Stackoverflow 答案。我希望您分享您对如何在不重新初始化类的情况下通过 PageFactory 搜索再次抛出 StaleElementReferenceException 的元素的研究?
  • @BreaksSoftware 很高兴听到这个消息。谢谢
  • 重新初始化页面类时工作:)
  • 这是一个非常糟糕的答案,会导致您走错路,同时似乎可以解决问题。如果您没有使用 @CachLookup 注释,则不需要重新初始化该类,您只需再次使用 WebElement,将 WebElement 绑定到 DOM 中的元素的 Java 代理类将再次处理查找该元素.重新初始化然后再次使用 WebElement 可能看起来有效,但这不是因为您重新初始化了该类,而是因为您再次搜索了该元素。
【解决方案2】:

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

如果你很不幸,在元素被找到到元素被点击之间的瞬间,元素变得陈旧,你会得到这个错误。不幸的是,如果 PageFactory 代码已经过时并抛出异常,则不会尝试再次查找该元素。

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 很好,但该解决方案专门询问了在使用页面工厂时处理陈旧元素异常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多