Page Factory Design Pattern (Enhanced POM)

Selenium Page Factory Pattern is like an extension to Page Object Model , but Page Factory is much enhanced model. To start with, we just need to import package ‘org.openqa.selenium.support.PageFactory’

"Factory class can be used to make using Page Objects simpler and easier".

We use Page Factory pattern to initialize web elements which are defined in Page Objects.

We should initialize page objects using initElements() method from PageFactory Class as below, Once we call initElements() method, all elements will get initialized. PageFactory.initElements() static method takes the driver instance of the given class and the class type, and returns a Page Object with its fields fully initialized.

Home homePage = new HomePage(driver);
PageFactory.initElements(driver, homePage);

Or,

// To initialize elements.
HomePage homePage = PageFactory.initElements(driver, HomePage.class);

Or, as a constructor for page class as below:

public HompePage(WebDriver driver) {           
this.driver = driver; 
PageFactory.initElements(driver, this);
}

We should preferably use a constructor which takes a WebDriver instance as its only argument or falling back on a no-arg constructor. An exception will be thrown if the class cannot be instantiated.

Page Factory will initialize every WebElement variable with a reference to a corresponding element on the actual web page based on “locators” defined. This is done by using @FindBy annotations.

Annotations?

In Page Factory, Annotations are used to give descriptive names for WebElements to improve code readability. And annotation @FindBy is used to identify Web Elements in the page.

By default, PageFactory will search for elements on the page with a matching id attribute, If that fails, then it will search by the name attribute. But as we need more control over identifying elements in the HTML page and mapping them to our Page Object fields. One way to do this is to use the @FindBy annotation, as shown in the following code:

The @FindBy annotation supports all the other locators strategies that we use:
id, name, className, css, xpath, tagName, linkText and partialLinkText

We can either use this annotation by specifying both "How" and "using" or by specifying any one of the location strategies (Eg: "id")

@FindBy(how = How.ID, using = "username") 
private WebElement userName;

We can re-write the above one as below:

@FindBy(id="username")
private WebElement userName;

And

To work with class name, we will define as below:

@FindBy(className=".input.username")
private WebElement userName;

When we have multiple elements (list of WebElements), we can initialize them using PageFactory as below :

@FindBy(tagName = "mylist") 
private List<WebElement> links;

Every time when a method is called on a WebElement, the driver will first find it on the current page and then simulate the action on the WebElement. There are cases where we will be working with a basic page, and we know that we will find the element on the page every time we look for it, In such cases we can use annotation ‘@CacheLookup‘ which is another annotation in page factory

@FindBy(name="username")
@CacheLookup
private WebElement userName;

What is @CacheLookup annotation in PageFactory?

We will mark annotation @CacheLookup to WebElements to indicate that it never changes (that is, that the same instance in the DOM will always be used)
CacheLookup attribute can be used to instruct the InitElements() method to cache the element once its located and so that it will not be searched over and over again – this is useful when the elements that are always going to be there
(For AJAX based applications, it may not work where the DOM changes based on user action on the page). Otherwise every time when we use a Web Element the WebDriver will go and search it again

But whenever we use @CacheLookup annotation, we will be losing one of the page factory benefit as it will find the element once and then keep a reference to it, hence, we are more likely to see StaleElementExceptions.

AjaxElementLocatorFactory

AjaxElementLocatorFactory is a lazy load concept in Page Factory pattern to identify WebElements only when they are used in any operation i.e. a timeOut for a WebElement can be assigned to the Object page class with the help of AjaxElementLocatorFactory.

Example:

/*** 
* Constructor 
* @param driver an instance of WebDriver 
*/
public int TimeoutValue = 30;
public SearchResultsPage(Webdriver driver) { 
    PageFactory.initElements(new AjaxElementLocatorFactory(driver, TimeoutValue), this);
}

The above code will wait for maximum of 30 seconds until the elements specified by annotations is loaded. If the element is not found in the given time interval, it will throw NoSuchElementException' exception.

Conclusion :

In fact, we can use the page object pattern without using the Page Factory class. The page object pattern simply abstracts business logic away from the physical structure of the pages. And the Page Factory class gives us the ability to use annotations which automatically find the elements on the page without specifying findElement.

Below is the sample code for Page Object Model in Selenium:

public class BasePage {

private By username = By.id("username");
private By password = By.id("password");
private By loginBtn = By.name("loginbtn");

  public void userLogin(String userName, String password) {
        driver.findElement(username).sendKeys("testuser");
        driver.findElement(password).sendKeys("testpassword");
        driver.findElement(loginBtn).click();
  }
}

And the below is the simple code written using Page Factory in Selenium:

public class BasePage {
  @FindBy(id= "username") private WebElement userName;
  @FindBy(id= "password") private WebElement password;
  @FindBy(id= "login") private WebElement loginBtn;

  public void userLogin(String userName, String password) {
    userName.sendKeys(userName);
    password.sendKeys(password);
    loginBtn.click();
  }
}
Selenium Tutorials: 

Comments

This is really good explanation. By reading this i got my existing problem solved. Thanks

Thanks for sharing great information in your blog. Got to learn new things from your Blog . It was very nice blog to learn about Selenium

1. How can we use page factory elements when we need to copy a group of elements to a list array(List<Web Element>) ?
2. How can we manipulate explicit waits for the elements where we need to check invisibility of those elements ?

How this Page Factory Pattern is useful?

Can you please provide more details abount AjaxElementLocatorFactory

PageFactory.initElements(new AjaxElementLocatorFactory(driver, TimeoutValue), this);

usually we pass driver as parameter but you mentioned - new AjaxElementLocatorFactory(driver, TimeoutValue)

its very good site n well display.but i need some real time exa
mples

Which web element initialisation is good ? I mean as a constructor or in Test Class.

Thanks for sharing this information. It's very useful and easy to understand.

In another article relating to Selenium test framework, it is said that the UI element locators could by put as key-value properties in UI map file. But if getting locator from the property files, they are imported as string variables and thus not able to be used in annotation"@FindBy".

Is there a way to import UI map property files together with page factory? Looking forward to seeing your reply.

Sincerely
Jonathan

Hi,

<div id=“product”>sdfsf</div><div id=“product”>abc</div><div id=“product”>vdvd</div><div id=“product”>dcd</div><div id=“product”>cdcd</div> In that how to select Random Input

Add new comment

CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.