Already , I have covered cause and ways of handling StaleElementReferenceException in detail. You can find the link of that post below:-
StaleElementReferenceException – Element’s “Reference” Stales – Get New Reference Of Element
Above post gives you a detailed information about :-
- What is StaleElementReferenceException?
- What are causes of StaleElementReferenceException ?
- What are the ways of handling StaleElementReferenceException ?
- Did use of Sleep for a thread help in handling StaleElementReferenceException?
- Did PageFactory help in handling StaleElementReferenceException ?
- How Retry mechanism to relocate WebElement may help in best way?
In this post, I am going to explain in detail – How PageFactory could resolve StaleElementException to an extent and where it may fail.
Note here that I am using term “PageFactory“. Many people say using Page Object Model (POM) we can hanle StaleElementReferenceException which is not correct.
Working Mechanism of PageFactory
- PageFactory is a default mechanism provided by Selenium WebDriver to implement Page Object Model using FindBy , FindBys and FindAll annotations. It helps to remove some boiler-plate code from your Page Objects.
- As per official document, FindBy and related annotations are used to mark a field on a Page Object to indicate an alternative mechanism for locating the element or a list of elements. We can either use this annotation by specifying both “how” and “using” or by specifying one of the location strategies (eg: “id”) with an appropriate value to use. For example :-
@FindBy(id= "email_create") protected WebElement emailAddress;
- PageFactory instantiates an instance of the given class, and set a lazy proxy for each of the WebElement andList<WebElement> fields that have been declared.
- PageFactory will search for an element on the page that matches the field name of the
WebElement
in the class. It does this by first looking for an element with a matching ID attribute. If this fails, the PageFactory falls back to searching for an element by the value of its “name” attribute. - To change how the element is located, use the above annotations with locating strategy.
- By default, the element or the list is looked up each and every time a method is called upon it. For example:- If we have a button web element and we call “click” N times on that button, WebDriver will look for element freshly N times. You no need to worry to initialize web elements once you use initElements() method of PageFactory. You will not face NullPointerException as well as StaleElementReferenceException. PageFactory helps a lot in automating AJAX-heavy applications because of this feature.
- We can change default behavior of looking for element every time using @CacheLookup. We can use this if page is static.
Now you should get clear concept that how PageFactory helps to avoid StaleElementException to an extent. Plain Page Object Model(POM) can not help you. In that case you need to go for retry mechanism.
Let’s do an example in which we will see how PageFatory resolves StaleElementReferenceException.
Test Scenario to be automated :-
- Load URL “https://github.com/login”.
- Type wrong username.
- Type wrong password.
- Click on submit.
- Type correct username.
- Type correct password.
- Click on submit.
package StaleElementException; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.Test; import io.github.bonigarcia.wdm.WebDriverManager; public class StaleElementHandling { @Test public void main() throws InterruptedException { // Setup browser WebDriverManager.chromedriver().setup(); WebDriver driver = new ChromeDriver(); // Open URL driver.get("https://github.com/login"); // locate and type user name WebElement username = driver.findElement(By.id("login_field")); username.sendKeys("amod"); // locate and type password WebElement pass = driver.findElement(By.id("password")); pass.sendKeys("amod"); // locate and click on submit WebElement sub = driver.findElement(By.xpath("//input[@value='Sign in']")); sub.click(); Thread.sleep(10000); // again type user name username.sendKeys("amod"); } }
Output :-
Starting ChromeDriver 81.0.4044.69 (6813546031a4bc83f717a2ef7cd4ac6ec1199132-refs/branch-heads/4044@{#776}) on port 5084 Only local connections are allowed. Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code. May 01, 2020 4:36:11 AM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: W3C FAILED: main org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document (Session info: chrome=81.0.4044.122) For documentation on this error, please visit: https://selenium.dev/exceptions/#stale_element_reference
So ,we get StaleElementReferenceException at line username.sendKeys(“amod”); because we tried to use a reference which belonged to old DOM. DOM changed when we passed wrong username and password. I have explained it very well in StaleElementReferenceException – Element’s “Reference” Stales – Get New Reference Of Element .
Now we know the reason of occurring StaleElementReferenceException and also unique feature of PageFactory to look for web element every time whenever a method is called on it. Are you able to connect dots? This problem can be solved using PageFactory. Let’s try it.
Create a page class and initialize its WebElement/s :-
package StaleElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class GitHubLoginPage { WebDriver driver; @FindBy(id = "login_field") public WebElement username; @FindBy(id = "password") public WebElement password; @FindBy(xpath = "//input[@value='Sign in']") public WebElement submit; public GitHubLoginPage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); } }
Use above Page Object class in test as below :-
package StaleElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import io.github.bonigarcia.wdm.WebDriverManager; public class StaleElementHandling2 { public static void main(String[] args) throws InterruptedException { // Setup browser WebDriverManager.chromedriver().setup(); WebDriver driver = new ChromeDriver(); driver.get("https://github.com/login"); // Creating object of page class which will initialize web elements GitHubLoginPage lp = new GitHubLoginPage(driver); lp.username.sendKeys("amod"); lp.password.sendKeys("dsds"); lp.submit.click(); Thread.sleep(5000); // Same element lp.username.sendKeys("amod"); lp.password.sendKeys("dsds"); lp.submit.click(); } }
You will not face StaleElementException becuase PageFactory will look for WebElement again after you provided wrong credentials and DOM was changed. But you may face this exceptions many times in angular and react applications where Web page and its components refreshes frequently.
More you understand an application , More stable script you can write.
If you have any doubt, feel free to comment below.
If you like my posts, please like, comment, share and subscribe.
#ThanksForReading
#HappyLearning
You can find all Selenium related post here.
You can find all API manual and automation related posts here.
You can find frequently asked Java Programs here.
Very well explained.. Thanks.. 🙂
Hi Amod,
When I launch browser and navianav to my application I will click on one link which will redirect to a next page. This operation we are doing in each and every test case. But after some 10 to 15 test cases I am getting StaleElementReference Exception even though there is no page refresh (the element which we are clicking is the first element on the webpage) and we are laughing browser for each and every test case. And even though page is getting loaded completely it’s unable to get an element.
Could you please let me know the cause of issue and how can I resolve it as it’s affecting our nightly batch run. And one more our system is also not going to sleeping mode, it will be active only.
Thanks in advance, waiting for your response.
Hello,
Are you using PageFactory concept? If not, implement it.
But you may get StaleElementReference even after using PageFactory. Suppose you click on a link, you dont see page is being refreshed but some ajax calls happen. If WebDriver finds any element in between that and stores it, that reference will go stale when ajax calls are completed. You can use javascript to get page loading status as completed or proper wait.
Thanks
Amod
We are using PageFactory… Thanks for your suggestion I will try with JavaScript.
Even I am getting Stale Element Reference Exception on Page Object Model.
Yes you can get if webdriver searches for element before page is completely loaded or ajax call is in progress or dynamic application. Page object model says webdriver to locate element if page is refreshed but not smart enough to know when should actually start locating. SO its your responsibility to use proper waits as well.
Very well explained. 🙂
findelements used inside forloop and click part is moved out of these for loops, thanks
Yes, while loop was creating problem.
Issue is solved through code by changing while loop to for loop and adding another for loop inside and using find elements along with counter variable,
hi Amod, could you please suggest the solution pls..its bit urgent
We need to debug it to know actually where it is getting null.
Hi Amod ,
I am facing issue with staleelement issue from 5days, can u suggest how to update in my code https://stackoverflow.com/questions/44471715/element-not-found-in-cache-perhaps-the-page-has-changed-since-it-has-lookedup-s/44476374#44476374
Pls help
Zareena
Try to do a findElement each time before you use the element. i.e put the line
java.util.List ListPath1 = driver.findElements(By.xpath((ReadPropertyFile.readProperty(“ClickNamePath”))));
inside the for loop. What is happening as Amod explained above that address of elements get updated. So if you put the findElements line inside the for loop you will have the latest address and it may solve the problem
give it a try
Hello,
Yours is not exactly stale exception. You have used click in a loop. Once it clicks and den go back to loop. Click changes tha page. This is causing issue.
Awesome explanation Amod…
Thanks Sanjay.
Thanks Amod for explaing the reason behind this exception with a very nice example
So we need to search the element again on the page to get the correct addres..
Instead of using @Findy notation and Pagefactory….
Cant we just put a simple find element like done on this page below…
http://toolsqa.com/selenium-webdriver/page-object-model/
public static WebElement username(WebDriver driver){
element = driver.findElement(By.id(“username”));
return element;
}
is there a difference between the one used by you where we used FindBy and Pagefactory compared to this one where we just do a findElement in the Pageobject class so each time you refer to the element it will be searched again so always correct address would be returned
Thanks Gaurav.
Awesome Amod Bhai…
Thanks Kamaraju.
Thanks Amod. This was much needed article. And once again your simple and easy explanation has cleared all doubts regarding this exception very well. Awesome
Thanks Nidhi.