How PageFactory Could Help to Handle StaleElementReferenceException

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 :-

  1. What is StaleElementReferenceException?
  2. What are causes of StaleElementReferenceException ?
  3. What are the ways of handling StaleElementReferenceException ?
  4. Did use of Sleep for a thread help in handling StaleElementReferenceException?
  5. Did PageFactory help in handling StaleElementReferenceException ?
  6. 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 :-

  1. Load URL “https://github.com/login”.
  2. Type wrong username.
  3. Type wrong password.
  4. Click on submit.
  5. Type correct username.
  6. Type correct password.
  7. Click on submit.

Selenium-Java Code :-

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.

24 thoughts on “How PageFactory Could Help to Handle StaleElementReferenceException

  1. 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.

    1. 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

    1. 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.

  2. 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,

    1. 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

    2. 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.

  3. 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

  4. 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

Leave a Reply

Your email address will not be published. Required fields are marked *