How can I handle StaleElementReferenceException in Appium using PageFactory when the execution is too fast? I’m getting the StaleElementReferenceException error with the message ‘The element does not exist in DOM anymore’ while trying to return the attribute from a PageObject method. Additionally, I’m unable to store the element reference for further interaction with the element, and if I do interact with the element, it throws the StaleElementReference Exception.
Partial Solution for The Problem
StepDefinition Class:
// connectivity check success message
private static final String CONNECTIVITY_CHECK_SUCCESS_MESSAGE = "green_Connectivity check";
// asserts that the connectivity check has passed
@And("The connectivity check should be passed")
public void theConnectivityCheckShouldBePassed() {
softAssert.assertEquals(dayPrepPage.getConnectivitySuccessfulMessage(), CONNECTIVITY_CHECK_SUCCESS_MESSAGE);
}
PageObject Class:
// content-desc String
private static final String CONTENT_DESCRIPTION_ATTRIBUTE = "content-desc";
// locates the element using PageFactory
@AndroidFindBy(accessibility = "green_Connectivity check")
@CacheLookup
private WebElement _connectivityCheckPass;
// returns the success message of the connectivity check element
public String getConnectivitySuccessfulMessage() {
return waitForElement(_connectivityCheckPass);
}
// finds and returns the content-desc attribute of the element
public String waitForElement(WebElement element) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(60));
return wait.pollingEvery(Duration.ofNanos(500))
.ignoring(StaleElementReferenceException.class)
.until(ExpectedConditions.refreshed(
ExpectedConditions.visibilityOf(element)
)).getAttribute(CONTENT_DESCRIPTION_ATTRIBUTE);
}
The problem with the above solution is that it is too flaky and highly dependent on the polling time of the WebDriver Wait. A little change to polling or application behaviour will break the test case.
Desired Solution to The Problem
ElementWrapper Class
public class ElementWrapper {
private final AndroidDriver driver;
private final By locator;
private WebElement element;
public ElementWrapper(AndroidDriver driver, By locator) {
this.driver = driver;
this.locator = locator;
}
public WebElement get() {
if (element == null || isStale()) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(40));
wait.pollingEvery(Duration.ofNanos(5000));
element = wait.until(ExpectedConditions.presenceOfElementLocated(locator));
}
return element;
}
public boolean isStale() {
try {
element.isEnabled();
return false;
} catch (NoSuchElementException | StaleElementReferenceException e) {
return true;
}
}
}
Waiting Class
public WebElement waitForPresenceOfElement(By element) {
try {
ElementWrapper elementWrapper = new ElementWrapper(driver, element);
WebElement item = elementWrapper.get();
System.out.println("Found Element: " + item.getText() + "Content Description: " + item.getAttribute("content-desc"));
return item;
} catch (Exception e) {
logger.logError(String.format("TimeoutException: Elements not visible: " + e.getMessage()));
}
return null;
}
I want to be able to store the reference of the element or cache it and use it when required by checking that if the element is stale then try to locate the element again and interact with it.
Failed Approaches to The Problem
I tried to find the element directly by not using the page factory for more control but as the execution is lightning fast even if I do find the element I am unable to perform any action on it.
public WebElement retryWhileLoop(By locator, int timeToRetry) {
WebElement foundElement = null;
int repeat = 0;
while (repeat <= timeToRetry) {
try {
foundElement = driver.findElement(locator);
break;
} catch (StaleElementReferenceException e) {
e.printStackTrace();
}
repeat++;
}
if (foundElement == null) {
throw new NotFoundException("The element was not located: " + connectivityCheckPass.toString());
}
return foundElement;
}
Don’t hesitate to ask for more information or invite me for a call. I will be more than happy to collaborate to figure this out. Thank you.