PageFactoryモデルを学習しようとしています。 initElements
を実行すると、WebElementsが配置されるという事実を理解しました。たとえば、Web要素をクリックしたため、DOM内の他のWeb要素の1つに変更があったとします。さて、明らかに私はここでStaleElementReferenceException
を取得します。この問題をどのように解決しますか?
DOM内のWebElementのプロパティが変更される可能性があるという事実を知っている特定のWebElementをもう一度見つける必要がありますか?またはこれを処理する別の方法はありますか?
StaleElementReferenceException extends WebDriverException これは、要素の以前の参照がstaleになり、要素参照がページのDOMに存在しなくなったことを示します。
StaleElementReferenceException
に直面する一般的な理由は次のとおりです:ID
または他の属性を持つ(新しい)要素に置き換えられました。findElement()
またはfindElements
を使用して要素を再度探すことです。initElementsを実行すると、WebElementsが検索されます:initElements()
メソッドを呼び出すと、すべてのWebElementsそのページのが初期化されます。例えば、
_LoginPageNew login_page = PageFactory.initElements(driver, LoginPageNew.class);
_
このコード行は、オートメーションスクリプトから呼び出されるときはいつでも、どこでも、_LoginPageNew.class
_のスコープ内で定義されたすべての静的WebElementsを初期化します。
Web要素をクリックしたため、DOM内の他のWeb要素の1つに変更がありました:これはほぼ可能です。
<input>
_タグでclick()
を呼び出しても、 --のWebElementsの変更はトリガーされません。 HTML DOM 。<button>
_タグまたは_<a>
_タグでclick()
を呼び出すと、JavaScriptまたはAjaxが呼び出され、削除される可能性があります。要素、または(前の)要素を同じID
または他の属性を持つ(新しい)要素に置き換えることができます。したがって、WebDriverがStaleElementReferenceExceptionをスローすると、要素がまだ存在していても、参照が失われます。現在の参照を破棄し、DOMに接続されたときにWebElementをもう一度見つけて置き換える必要があります。つまり、initElements()
メソッドを使用してクラスを再初期化する必要があります。このメソッドは、そのページで定義されているすべてのWebElementsを再初期化します。
古い要素が新しい同一の要素に置き換えられた場合、単純な戦略は、 WebDriverWait を ExpectedConditions と組み合わせて呼び出して、要素を探すことです。
関連する詳細な議論は次の場所にあります。
このディスカッションの参考資料は次のとおりです。
これは、PageFactory実装の既知の問題です。
運が悪ければ、要素が見つかってから要素がクリックされるまでの瞬間に要素が古くなると、このエラーが発生します。残念ながら、PageFactoryコードは、要素が古くなって例外をスローした場合、その要素を再度検索しようとはしません。
これをPageFactoryのバグとして分類します。要素が古くなった場合は、要素を自動的に再検出する必要があります(@CacheLookupアノテーションが使用されている場合を除く)。
InitElementsをリコールするという提案は何も修正しません。問題の要素にJavaプロキシクラスをバインドするため、要素を1回だけ初期化する必要があります。ページファクトリの実装はStaleElementReferenceExceptionsの可能性を削除します(したがって、これがバグである理由)
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();
}
});
}