Reputation: 1087
Click Method keeps returning Stale Element Exception
?
Sometimes the method will click on the intended link:-
public @FindBy(xpath = ".//div[@class='category_menu']//a[text()='Supercars »']") WebElement link_Supercars;
However I frequently get the following exception
:-
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
Method:
public void clickSupercarsLink() throws Exception {
this.wait = new WebDriverWait(driver, 30);
Boolean elementPresent = wait.until(ExpectedConditions.elementToBeClickable(link_Supercars)).isEnabled();
try {
if (elementPresent == true) {
link_Supercars.click();
}
} catch (Exception e) {
System.out.println("Exception! - could not click on supercars link: " + e.toString());
throw (e);
} finally {
}
}
Any ideas on how i can improve this method?
Thanks for your help!
Upvotes: 1
Views: 1377
Reputation: 517
As partially said above, this exception occurs when the WebElement you are trying to use has been updated by the app between the moment you locate it and the moment you are trying to interact with it.
A solution could be to locate it again in your catch statement :
public void clickSupercarsLink() throws Exception {
this.wait = new WebDriverWait(driver, 30);
Boolean elementPresent = wait.until(ExpectedConditions.elementToBeClickable(link_Supercars)).isEnabled();
try {
if (elementPresent == true) {
link_Supercars.click();
}
} catch (StaleElementReferenceException elementUpdated){
link_Supercars = driver.findElement(myLocator);
if (elementPresent == true) {
link_Supercars.click();
}
} catch (Exception e) {
System.out.println("Exception! - could not click on supercars link: " + e.toString());
throw (e);
} finally {
}
This problem is the reason why I'm not using PageFactory whit the annotation @FindBy to locate my elements. It is not stable if you are automating an app that have a lot of javascript and/or AJAX calls.
Hope it helps
EDIT : Explaination of how I am working
I'm creating my pageObjects by defining only the locators in the class :
By myElement = By.id("myId");
Once you have that, you can simply use (for instance) :
driver.findElement(myElement).click();
It's still not how I am working because it's pretty heavy to always define your waits and then the location of the element, and so on.
I created an SeleniumUtils class so that I just have to write something like
SeleniumUtils.clickElement(myElement);
And in this method, I am doing everything that is needed to be sure I can click on the element. wait that is clickable, and sometimes actions that are a bit more application dependent.
I'll add a little note to say that it's the way I'm working. I don't say it's perfect or whatever else, but since I have defined those utils, I rarely have to write waits anywhere in the application, which help me to automate it faster.
Upvotes: 2