Testim Copilot is here | Learn More

Page Factory in Selenium: Everything You Need to Know

The end goal of test automation is to ease the process of testing web pages. If test automation isn't written…

Author Avatar
By Erin,

The end goal of test automation is to ease the process of testing web pages. If test automation isn’t written in a well-structured manner, then the testing process becomes ambiguous and ineffective. In Selenium, Page Factory optimizes test instances created using the page object model (POM). The POM ensures that tests are written in a readable and maintainable form. This page object makes it easier to see what the code is trying to do at a glance, and Page Factory initializes this process. 

In this article, we’ll learn about the use of Page Factory. We’ll also learn how to implement it within a project.

What is Page Factory?

Page Factory is a factory class in Selenium for implementing the Page Object Model. It’s an optimized version of the POM for Selenium WebDriver, which follows the separation techniques for handling the object repositories and the test cases. It’s a class that extends from the web driver classes. It allows annotations to build up a set of web elements. This makes it faster to create initial page objects.

Let’s look at a sample code block written in Java using the POM in Page Factory. It shows a class that has been created for the home page of a website. An annotation FindBy exists within the class. We’ll go over it in detail later in this article, but it’s used to locate elements on the web page.

public class HomePage {
  @FindBy(id= "username") private WebElement Username;
  @FindBy(id= "password") private WebElement Pword;
  @FindBy(id= "login") private WebElement loginButton;

  public void userLoginDetails(String Username, String Pword) {
	Username.sendKeys(Username);
	Pword.sendKeys(Pword);
	loginButton.click();
  }
}

To further understand Page Factory, let’s look at how it differs from Page Object Models.

What Is the Difference Between Page Factory and the Page Object Model?

The Page Object Model is a design pattern used to create an object repository for the web elements accessible on a web page. It uses a By annotation to describe page objects, and every object needs to be initialized. POM also has cache storage.

Page Factory, on the other hand, is a class that simply implements the POM. In terms of optimization, Page Factory is more optimized than the POM. It uses a FindBy annotation for page objects. Each object doesn’t require initialization like POM, and all elements are initialized with initElements(). It doesn’t have cache storage because it doesn’t need it. 

To provide more context on the difference in annotations and methods used, let’s look at how they both locate the search box web elements from the Google home page. To locate web elements for Page Factory, @FindBy is used, while for the POM, the method @FindElements is used. 

@FindBy(id= "input")
WebElement GoogleSearchBox;

The line above shows that the annotation points directly to a specific locator ID, while @FindElements requires many more pointers to get a particular element.

Annotations in Page Factory

To identify UI elements for web pages, it’s essential to develop a location strategy. Annotations can also be used to do this. Some of these annotations have been highlighted earlier. Let’s look at them here:

  • @FindBy: This is used to identify web elements with just one defined criterion. It can be used to locate the following: id, name, className, CSS, XPath, tagName, linkText, and partialLinkText.
  • @FindBys: This is used to point to web elements with more than one criteria and must match all. An AND conditional relationship is used to identify the web elements based on the various criteria defined.
  • @FindAll: This is similar to the @FindBys, but it needs to match at least one of the criteria. In this case, an OR conditional relationship is used.
  • @CacheLookUp: The end goal of this annotation is to make the code execute faster. It’s used mostly for WebElements in a test case. For the specific element, it keeps the WebElement in the cache memory after the first time it’s run.

Expand Your Test Coverage

Fast and flexible authoring of AI-powered end-to-end tests — built for scale.
Start Testing Free

Initialization

After we locate the WebElements, we need to initialize them using InitElements(). This always occurs after the @FindBy annotation. The line below shows how the initElement() is used.

PageFactory.initElements(WebDriver driver, java.lang.Class.pageObjectClass);

In Page Factory, there is also a concept called Lazy Load, which uses AjaxElementLocatorFactory. It can be used when an element must be found for an operation and pass a timeout value. It can also be used when the application in the picture uses Ajax elements. 

So let’s look at how to use Page Factory with a specific example.

How to Use Page Factory in Selenium

This guide will use Java to implement Page Factory in Selenium. The following steps are necessary to follow this guide.

After installing the components listed above, you can now follow the next steps to learn how to use Page Factory.

Scenario

To fully explain this concept, we’ll use the scenario below:

  1. Open the Chrome browser.
  2. Open the URL https://google.com.
  3. Write Testing in the text box.
  4. Click Search.
  5. Close the browser.

Steps

To automate the test case above, we’ll first create a new Maven project. Next, let’s give both the groupID and attributeID the value PageFactoryID

Now, add the dependencies for Selenium and Junit. The {junit.version} and {selenium.version} should be replaced with the version on their website.

<dependencies>
        <!-- JUnit -->         
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Selenium -->

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-firefox-driver</artifactId>
            <version>${selenium.version}</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-support</artifactId>
            <version>${selenium.version}</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>${selenium.version}</version>
        </dependency>

    </dependencies>

Now that we’ve added the dependencies let’s define the project’s structure.

Project Structure

Packages

In the POM, there are recommended sets of packages for projects, which are the webpage and test packages. For this project, create a package with the name com.google.page. Within your created package, com.google creates two other packages: webpages and tests

Classes

Next, let’s create a class named GoogleHomePage. This is where the locators and methods for the homepage will be stored. This class imports the webdriver, webelement, annotation, and pagefactory.

package com.google.webpages; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.WebElement; 
import org.openqa.selenium.support.FindBy; 
import org.openqa.selenium.support.How; 
import org.openqa.selenium.support.PageFactory; 

public class GoogleHomePage { 
// WebDriver reference variable. 
   WebDriver driver; 
// Pass WebDriver as an input to a the constructor 
   public GoogleHomePage( WebDriver driver ) { 
     this.driver = driver; 
// Call initElements() method by using PageFactory reference and pass driver and this as parameters. 
    PageFactory.initElements( driver, this); 
   } 
// Locate elements using the required locators 
   @FindBy(how = How.NAME, using = "q") 
   WebElement searchBox; @FindBy(how = How.NAME, using = "btnK") 
    WebElement submit; 

 public void search() 
 { 
    searchBox.sendKeys("Testing"); 
 } 
public void submit() 
{ 
  submit.click(); 
 } 
}

Testing

We have now created the class for the page; the next class to create is for the test instance. Create a class named GoogleHomeTest. In this class, the webdriver objects are used to open the chrome browser, implement waits, and then the URL is defined. Note: this class is created within the com.google.test page.

package com.google.tests; 
import java.util.concurrent.TimeUnit; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.chrome.ChromeDriver; 
import org.testng.annotations.AfterTest; 
import org.testng.annotations.BeforeTest; 
import org.testng.annotations.Test; 
import com.google.webpages.GoogleHomePage; 

public class HomeTestClass 
{ 
  static WebDriver driver; 
@BeforeTest 
public void setUp() 
{ 
   driver = new ChromeDriver(); 
   driver.manage().window().maximize(); 
  String url = "https://www.google.com"; 
  driver.get(url); 
  driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 
 } 
@Test(priority = 0) 
public void googleSearch() 
{ 
// Create an object of GoogleHomePage class. 
   GoogleHomePage gs = new GoogleHomePage(driver); 
    gs.title(); // this calls the title method. 
    gs.search(); // this calls the search method. 
    gs.submit(); // this calls the submit method. 
 } 
@AfterTest
public void closing() 
{ 
  HomeTestClass.driver.quit(); 
 } 
}

So the test ends by closing the chrome driver. Now you’ve implemented Page Factory in Selenium!

Conclusion

When carrying out test automation, consider implementing Page Factory in Selenium. And remember to use @CacheLookup within InitElements(). This will ensure the web elements load just once and do not have to reload whenever the method is called. Also, note that asides from single web elements, Page Factory also locates lists of elements.

Tools for test automation, such as Testim, are helpful in areas like these. So take advantage of the 14-day trial and learning resources, and try Testim for free now!