Reputation: 36654
I run web E2E tests (using cucumber, junit, selenium webDriver) on Ubunto.
my test fails sporadically when using remoteWebDriver (never fails with 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
I thought I have bypassed this exception when I refactored my code to this:
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));
}
how can i stabilize this test further?
Update
I'm trying mentallurg
solution. But is this well structured?
public String getButtonTextAfterWait(final By by) {
String currentText;
try {
currentText = tryToGetText(by);
} catch (StaleElementReferenceException ex)
{
currentText = tryToGetText(by);
}
return currentText;
}
Upvotes: 1
Views: 2330
Reputation: 301
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)));
}
Upvotes: 1
Reputation: 5207
@EladBenda: Not really. You should do that within a loop. But you don't need to code the loop. Use FluentWait instead. You only need to convert your method "getButtonTextAfterWait" into an ExpectedCondition or a Predicate or a Function and pass it to FluentWait. You don't need to catch exceptions explicitly. You can do that via ...ignoring(...Exception.class), as you already do on the other place. It can look as follows:
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.
}
});
Upvotes: 0
Reputation: 5207
If you page is dynamic, following can happen.
Scenario 1. In the method "getSrcAfterWait", you located the element with "getElementAfterWaitForDisplay2". But before you call webElement.getAttribute("src"), the element changes on the page. And when you call webElement.getAttribute("src"), the "webElement" points to an already obsolete (not more existing) element. This leads to StaleElementReferenceException.
Scenario 2. May be you have some kind of animation. So that periodically a new instance of element is create many times. The "getElementAfterWaitForDisplay2" always find an element for "By" condition, but time to time it is a newer object on the page. After you located the element and before you call webElement.getAttribute("src") there was a new instance created on the page (in the DOM). So that your located variable refers to the already obsolete instance.
The simple solution in both cases: catch the exception and locate the object again.
More complex solution, but more generic: use proxy objects and implement exception handling and locating there.
Upvotes: 1