3

While using Pagefactory I am directly declaring WebElement as below.

@AndroidFindBy(accessibility = "androidLocator")
@iOSFindBy(accessibility = "iosLocator")
private MobileElement element;

But, is there a way out to handle StaleElementReference exception as I am not using any By object here. All the solutions that I could figure out asks me to use locators as object of By.

I wanted to write a generic method in a parent class for all the page classes which handles StaleElementReferenceException. But the problem is I can only pass the reference as a WebElement and not as a By object which beats the purpose of reinitialize the WebElement.

I could find the below solution :

FluentWait<MobileDriver<MobileElement>> wait = new FluentWait<MobileDriver<MobileElement>>(driver)
                        .withTimeout(20, TimeUnit.SECONDS).pollingEvery(500, TimeUnit.MILLISECONDS)
                        .ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class);
                wait.until(new Function<WebDriver, MobileElement>() {
                    @Override
                    public MobileElement apply(WebDriver driver) {
                        element.get
                        MobileElement element = driver.findElement(by);
                        return element;
                    }
                });

But the same problem occurs here too. I need to pass the reference as By object where as in PageFactory I have reference as WebElemrnt

0

4 Answers 4

1

You could use refreshed ExpectedCondition to wait for the element to be redrawn in the DOM

(new WebDriverWait(driver, 30)).until(ExpectedConditions.refreshed(ExpectedConditions.visibilityOf(element)));
Sign up to request clarification or add additional context in comments.

1 Comment

Not working even after implementing this. The new exception introduced is : Expected condition failed: waiting for condition (visibility of [[Android: uiautomator2] -> accessibility id: locator]) to be refreshed (tried for 20 second(s) with 500 MILLISECONDS interval
1

Whether it be Appium or plain old Selenium, my solution for stale element has always been to make sure I'm working with a freshly instantiated page object.

If you are sharing a page object across test methods, or if there is something that might change the state of the page, it can't hurt to re-initialize the page object.

You don't show your page object initialization code, though. What does your page initialization look like?

1 Comment

My page object initialisation looks like PageFactory.initElements(new AppiumFieldDecorator(driver, this);
0

You can put your command in a try...catch block and if you catch StaleElementReference Exception then refresh your page using driver.navigate.refresh() and perform the same action again.

If your element is going to be refreshed automatically after some time then you can also use ExpectedConditions for this scenario.

wait.until(ExpectedConditions.refreshed(ExpectedConditions.stalenessOf(element)));

6 Comments

As OP said he already has WebElement defined in POM, so driver.findElement will just cause you to use another locator object. And you can do click and sendKeys if the element is not stale, but if it is in stale state it will throw the StaleElementReference Exception, that's why I suggested to refresh the page in catch block so that the element gets reloaded into the DOM and then user can perform any action on it.
Refreshing the page is not a good option, as refreshing will delete all the previously filled data. Hence, the test case will fail.
Then you can handle the data filling part in an external method and put that method call in a try..catch block, if it throws StaleElementReference Exception for any of the element it will refresh the page and try to rewrite data in all the elements. If it's a multi step process and refreshing the page navigates you to the first page then this might not be a good idea but if you are staying on the same page, i think this should work. Other than that I don't see any other option then waiting for the element to get refreshed automatically, if there is any logic implemented to do that.
Ya got it. This might be helpful for browser automation. But if you look at my code snippet above, I am more focussed about native app automation using appium.
Can you try PageFactory.initElements(new AppiumFieldDecorator(driver, DEFAULT_WAIT_TIME, SECONDS), this); as suggested over here discuss.appium.io/t/…. I don't have much experience with appium but I try my best to understand.
|
0

You can use a try catch block, in try you can use the normal selenium method to wait and click. And then in catch you can use the JavascriptExecutor to click on the element.

private WebDriverWait webDriverWait;

public WebElement waitForElement(WebDriver driver, WebElement element) {
    try {
        webDriverWait = new WebDriverWait(driver, 10);
        webDriverWait.until(ExpectedConditions.elementToBeClickable(element));
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return element;
}

public void click(WebDriver driver, WebElement element) {
    try {
        waitForElement(driver, element).click();
    } catch (Exception ex) {
        ex.printStackTrace();
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].click();", element);
    }
}

I hope this solves your problem. Thanks.

1 Comment

As u can see in the question, it is appium code. So, javascript executor don't be handy here. More over I am not just concerned about click, it can be getText or and other method in the WebElement Class.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.