1. ホーム
  2. java

[解決済み] ランダム "要素が DOM に添付されなくなりました" StaleElementReferenceException

2022-04-30 03:45:31

質問

私だけならいいのですが、Selenium Webdriverは完全に悪夢のようです。 ChromeのWebdriverは現在使用できませんし、他のドライバもかなり信頼性が低い、またはそのように思われます。 私は多くの問題と戦っていますが、ここに1つあります。

ランダムに、私のテストが

"org.openqa.selenium.StaleElementReferenceException: Element is no longer attached 
to the DOM    
System info: os.name: 'Windows 7', os.arch: 'amd64',
 os.version: '6.1', java.version: '1.6.0_23'"

webdriverのバージョンは2.0b3を使っています。 FFとIEのドライバでこの現象が起こるのを見たことがあります。 私がこれを防ぐことができる唯一の方法は、実際の呼び出しを追加することです。 Thread.sleep 例外が発生する前に しかし、それは貧弱な回避策なので、誰かが私のエラーを指摘して、このすべてを良くしてくれることを期待しています。

解決方法は?

はい、もしあなたがStaleElementReferenceExceptionsで問題を抱えているのなら、それはレースコンディションが存在するからです。次のシナリオを考えてみてください。

WebElement element = driver.findElement(By.id("foo"));
// DOM changes - page is refreshed, or element is removed and re-added
element.click();

今、あなたが要素をクリックした時点で、要素参照はもはや有効ではありません。そのため、WebDriver は手を上げて、テストやアプリの作成者として何が起こるか起こらないかを正確に知っているべきあなたに、コントロールを委ねます。そのため、テストやアプリの作者としては、何が起こるか起こらないかを正確に把握しておく必要があります。そこで、DOM が変化しない状態になるまで、明示的に待つようにします。例えば、WebDriverWait を使って、特定の要素が存在するのを待ちます。

// times out after 5 seconds
WebDriverWait wait = new WebDriverWait(driver, 5);
    
// while the following loop runs, the DOM changes - 
// page is refreshed, or element is removed and re-added
wait.until(presenceOfElementLocated(By.id("container-element")));        

// now we're good - let's click the element
driver.findElement(By.id("foo")).click();

presenceOfElementLocated()メソッドは、以下のようになります。

private static Function<WebDriver,WebElement> presenceOfElementLocated(final By locator) {
    return new Function<WebDriver, WebElement>() {
        @Override
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    };
}

現在のChromeドライバが非常に不安定であることについて、あなたは正しいです。そして、Selenium trunkに書き直されたChromeドライバがあり、実装のほとんどが彼らのツリーの一部としてChromium開発者によって行われたことを聞いて満足することでしょう。

追記 別の方法として、上記の例のように明示的に待つのではなく、暗黙的な待ちを有効にすることができます。この方法では、WebDriver は指定されたタイムアウトまで常にループして、要素が存在するようになるのを待ちます。

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS)

しかし、私の経験では、明示的に待つ方が常に信頼性が高いです。