メインコンテンツへスキップ
SDETRole
SDETRole

用語集 · UI 自動化

StaleElementReferenceException

別名: stale element, stale element reference, ステイルエレメント, stale element exception

定義

要素を取得した後に DOM ノードが削除・置換された WebElement をテストが使ったときに発生する Selenium のエラーで、典型的には再レンダリング後に起こります。

StaleElementReferenceException は、コードが保持している要素がページ上にもう存在しないことを意味します。Selenium の WebElement は、ある特定の DOM ノードへの参照です。フレームワークがリストを再レンダリングした、ページが遷移した、AJAX の更新でセクションが置き換えられた、などの理由でアプリケーションがそのノードを削除すると、参照は何も指さなくなり、それに対するあらゆる呼び出しがこの例外を投げます。

例

WebElement firstRow = driver.findElement(By.cssSelector("table tbody tr"));

driver.findElement(By.id("sort-by-date")).click(); // table body is re-rendered

firstRow.getText(); // StaleElementReferenceException

画面上では要素はまったく同じに見えますが、それは新しいノードです。古い参照はもう使えません。

直し方

例外をキャッチするのではなく、必要になった時点で要素を探し直し、新しい状態になるのを待ちます。

By firstRow = By.cssSelector("table tbody tr");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));

WebElement before = driver.findElement(firstRow);
driver.findElement(By.id("sort-by-date")).click();

// Wait until the old node is gone, then look up the new one
wait.until(ExpectedConditions.stalenessOf(before));
String text = driver.findElement(firstRow).getText();

ほかにも有効なパターンがあります。

  • ページオブジェクトでは WebElement フィールドではなく By ロケーターを保持し、 各メソッドの中で要素を探します。
  • 値を読む前に、更新の完了を待ちます(スピナーが消える、行数が変わるなど)。
  • 長期間保持するリストを避けます。 再レンダリングを引き起こす項目をクリックしながら List<WebElement> をループ処理するのは、このエラーの典型的な原因です。ループのたびにインデックスや一意な属性で探し直しましょう。

Playwright でこの問題がほとんど起きない理由

Playwright の Locator はノードへの参照ではなくクエリです。操作やアサーションのたびに要素を解決し直すため、ステップ間で再レンダリングが起きても壊れません。ただし Playwright の低レベル API である ElementHandle は、切り離されたノードを指してしまうことがあり、それがドキュメントでロケーターの使用が推奨されている理由の 1 つです。

すべての呼び出しを「stale なら再試行」のループで包めばエラーは消えますが、本当の問題、つまりテストがページの安定を待っていないことを隠してしまいます。

キーワードを入力すると SDETRole 全体を検索できます。

Pagefind による全文検索 · ブラウザ内で動作します 検索ページを開く →