随机“元素不再附加到 DOM” StaleElementReferenceException

我希望这只是我,但Selenium Webdriver似乎是一个完全的噩梦。Chrome网络驱动程序目前无法使用,其他驱动程序非常不可靠,至少看起来是这样。我正在与许多问题作斗争,但这里有一个。

随机地,我的测试将失败,并带有

"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'"

我使用的是网络驱动程序版本 2.0b3。我已经看到FF和IE驱动程序发生这种情况。我能防止这种情况的唯一方法是在异常发生之前添加一个实际的调用。不过,这是一个糟糕的解决方法,所以我希望有人能指出我的错误,这将使这一切变得更好。Thread.sleep


答案 1

是的,如果您在使用 StaleElementReferenceException 时遇到问题,那是因为存在争用条件。请考虑以下情形:

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主干有一个重写的Chrome驱动程序,其中大部分实现都是由Chromium开发人员完成的,作为他们树的一部分。

或者,您可以启用隐式等待,而不是像上面示例中那样显式等待 - 这样WebDriver将始终循环,直到指定的超时等待元素出现:

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

然而,根据我的经验,明确等待总是更可靠。


答案 2

我已经能够使用这样的方法并取得了一些成功:

WebElement getStaleElemById(String id) {
    try {
        return driver.findElement(By.id(id));
    } catch (StaleElementReferenceException e) {
        System.out.println("Attempting to recover from StaleElementReferenceException ...");
        return getStaleElemById(id);
    }
}

是的,它只是不断轮询元素,直到它不再被认为是过时的(新鲜?)。并没有真正找到问题的根源,但我发现WebDriver对抛出这个异常可能相当挑剔 - 有时我明白,有时我不明白。或者可能是DOM确实在变化。

所以我不太同意上面的答案,即这必然表明测试写得很差。我已经把它放在新的页面上,我没有以任何方式与之互动。我认为DOM的表示方式或WebDriver认为过时的内容存在一些不平衡。


推荐