StaleElementReferenceException,即使我使用`FluentWait<>`

时间:2015-04-12 14:46:48

标签: java google-chrome selenium selenium-webdriver webdriver

我在Ubunto上运行web E2E测试(使用cucumber,junit,selenium webDriver)。

我的测试在使用remoteWebDriver时失败零星(从未使用local-webDriver失败)

Then banner image in preview html should be "p_1047_o_9075_banner_1423040308.png"


Failure 
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document

当我将代码重构为此时,我以为我绕过了这个异常:

    public String getSrcAfterWait(final By by) {
        WebElement webElement = getElementAfterWaitForDisplay2(by);
        String currentSrc = null;
        if (webElement != null) {
            currentSrc = webElement.getAttribute("src");
        }
        return currentSrc;
    }


 public WebElement getElementAfterWaitForDisplay2(final By by) {
        Wait<WebDriver> wait = new FluentWait<>(driver)
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);

        return wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }

我怎样才能进一步稳定这个测试?

更新

我正在尝试mentallurg解决方案。但这个结构合理吗?

  public String getButtonTextAfterWait(final By by) {
        String currentText;
        try {
            currentText = tryToGetText(by);

        } catch (StaleElementReferenceException ex)
        {
            currentText = tryToGetText(by);
        }
        return currentText;
    }

3 个答案:

答案 0 :(得分:1)

如果您的页面是动态的,可能会发生以下情况。

情景1。 在方法“getSrcAfterWait”中,您找到了带有“getElementAfterWaitForDisplay2”的元素。但在调用webElement.getAttribute(“src”)之前,元素会在页面上发生更改。当你调用webElement.getAttribute(“src”)时,“webElement”指向一个已经过时(不再存在)的元素。这导致StaleElementReferenceException。

情景2。 可能你有某种动画。因此,定期创建一个新的元素实例多次。 “getElementAfterWaitForDisplay2”总是找到“By”条件的元素,但不时地它是页面上的新对象。在找到元素之后,在调用webElement.getAttribute(“src”)之前,在页面上创建了一个新实例(在DOM中)。这样您所定位的变量就会引用已经过时的实例。

两种情况下的简单解决方案:捕获异常并再次找到对象。

更复杂的解决方案,但更通用:使用代理对象并实现异常处理和定位。

答案 1 :(得分:0)

@EladBenda:不是。你应该在循环中做到这一点。但是你不需要编写循环代码。请改用FluentWait。你只需要转换你的方法&#34; getButtonTextAfterWait&#34;进入ExpectedCondition或谓词或函数并将其传递给FluentWait。您不需要明确捕获异常。您可以通过...忽略(... Exception.class),就像您在其他地方已经做的那样。它可以如下所示:

Wait wait = new FluentWait(driver)
  .withTimeout(60, SECONDS)
  .pollingEvery(5, SECONDS)
  .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);

String text = wait.until(new Function() {
  public String apply(WebDriver driver) {
    WebElement element = driver.findElement(By.id("..."));
    return element.getText(); // or webElement.getAttribute("src")  etc.
  }
});

答案 2 :(得分:0)

public void waitForElementBeDisplay(WebElement element) {


    Wait wait = new FluentWait(driver).withTimeout(Duration.ofSeconds(30)).ignoring(StaleElementReferenceException.class).pollingEvery(Duration.ofSeconds(2));
    wait.until(ExpectedConditions.refreshed(ExpectedConditions.visibilityOf(element)));

}