web-dev-qa-db-ja.com

PageFactoryのStaleElementReference例外

PageFactoryモデルを学習しようとしています。 initElementsを実行すると、WebElementsが配置されるという事実を理解しました。たとえば、Web要素をクリックしたため、DOM内の他のWeb要素の1つに変更があったとします。さて、明らかに私はここでStaleElementReferenceExceptionを取得します。この問題をどのように解決しますか?

DOM内のWebElementのプロパティが変更される可能性があるという事実を知っている特定のWebElementをもう一度見つける必要がありますか?またはこれを処理する別の方法はありますか?

11
user2356679

StaleElementReferenceException

StaleElementReferenceException extends WebDriverException これは、要素の以前の参照がstaleになり、要素参照がページのDOMに存在しなくなったことを示します。


一般的な理由

  • StaleElementReferenceExceptionに直面する一般的な理由は次のとおりです:
    • 要素は完全に削除されました。
    • 要素はDOMにアタッチされなくなりました。
    • 要素が含まれていたWebページが更新されました。
    • (前の)要素はJavaScriptまたはAjaxCallによって削除され、同じIDまたは他の属性を持つ(新しい)要素に置き換えられました。
  • 解決策(古い)要素が新しい同一の要素に置き換えられた場合、簡単な戦略は、findElement()またはfindElementsを使用して要素を再度探すことです。

あなたの質問に答える

  1. initElementsを実行すると、WebElementsが検索されますinitElements()メソッドを呼び出すと、すべてのWebElementsそのページのが初期化されます。例えば、

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

    このコード行は、オートメーションスクリプトから呼び出されるときはいつでも、どこでも、_LoginPageNew.class_のスコープ内で定義されたすべての静的WebElementsを初期化します。

  2. Web要素をクリックしたため、DOM内の他のWeb要素の1つに変更がありました:これはほぼ可能です。

    • 例として、一般に、_<input>_タグでclick()を呼び出しても、 --のWebElementsの変更はトリガーされません。 HTML DOM
    • _<button>_タグまたは_<a>_タグでclick()を呼び出すと、JavaScriptまたはAjaxが呼び出され、削除される可能性があります。要素、または(前の)要素を同じIDまたは他の属性を持つ(新しい)要素に置き換えることができます。

結論

したがって、WebDriverStaleElementReferenceExceptionをスローすると、要素がまだ存在していても、参照が失われます。現在の参照を破棄し、DOMに接続されたときにWebElementをもう一度見つけて置き換える必要があります。つまり、initElements()メソッドを使用してクラスを再初期化する必要があります。このメソッドは、そのページで定義されているすべてのWebElementsを再初期化します。


解決

古い要素が新しい同一の要素に置き換えられた場合、単純な戦略は、 WebDriverWaitExpectedConditions と組み合わせて呼び出して、要素を探すことです。

関連する詳細な議論は次の場所にあります。


参考文献

このディスカッションの参考資料は次のとおりです。

12
DebanjanB

これは、PageFactory実装の既知の問題です。

運が悪ければ、要素が見つかってから要素がクリックされるまでの瞬間に要素が古くなると、このエラーが発生します。残念ながら、PageFactoryコードは、要素が古くなって例外をスローした場合、その要素を再度検索しようとはしません。

これをPageFactoryのバグとして分類します。要素が古くなった場合は、要素を自動的に再検出する必要があります(@CacheLookupアノテーションが使用されている場合を除く)。

InitElementsをリコールするという提案は何も修正しません。問題の要素にJavaプロキシクラスをバインドするため、要素を1回だけ初期化する必要があります。ページファクトリの実装はStaleElementReferenceExceptionsの可能性を削除します(したがって、これがバグである理由)

2
Ardesco

Stale element exceptionは2つの場合にスローされます

要素は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(); 
    } 
  }); 
}
1