services
A holistic approach that accelerates your current vision while also making you future-proof. We help you face the future fluidically.

Digital Engineering

Value-driven and technology savvy. We future-proof your business.

Intelligent Enterprise

Helping you master your critical business applications, empowering your business to thrive.

Experience and Design

Harness the power of design to drive a whole new level of success.

Events and Webinars

Our Event Series

Sommelier

Turntable

Featured Event
14 - 16 May
Convention Centre Dublin, Ireland
Our Latest Talk
By Kanchan Ray, Dr. Sudipta Seal
video icon 60 mins
About
nagarro
Discover more about us,
an outstanding digital
solutions developer and a
great place to work in.
Investor
relations
Financial information,
governance, reports,
announcements, and
investor events.
News &
press releases
Catch up to what we are
doing, and what people
are talking about.
Caring &
sustainability
We care for our world.
Learn about our ESG
initiatives.

Fluidic
Enterprise

Beyond Agility, the convergence of technology and human ingenuity.
talk to us
Welcome to digital product engineering
Thanks for your interest. How can we help?
 
 
Author
Coby Guo
Coby Guo
connect

“Think twice, code once.” - Anonymous. Quite clearly, whoever said this so aptly, was well and truly aware that while software runs on code, code itself runs on (or only after) being tested well enough. Within testing, test automation plays an important role, especially in agile projects. Page Object Model (POM) and Page Factory are among the most popular design patterns in test automation. These solutions are widely used in UI test automation and help develop excellent project frameworks. This design pattern:

  • makes it easier to build automation test scripts
  • makes automation code much cleaner and easier to read
  • reduces maintenance effort and redundant code

Can you even imagine the arduous task of maintaining 50K-class scripts without any automation design? It would be a nightmare for the company and the engineer. This article explains what Page Factory is, how it works in enterprise-level test automation, and how to build the foundation to customize it.

What are Page Object and Page Factory?

“If you automate a mess, you get an automated mess.” – Rod Michael

Question: You need to pick a shirt out of many clothes. How would you prefer to select it?

Design pattern in test automation – Page object vs. no page objectPic 1: PO vs. No PO

Scenario 1

The picture on your right: This is a pile of clothes. All the clothes are in a mess. You might need to spend some time finding the shirt.

Scenario 2

The picture on your left: The clothes are organized in a wardrobe. You can find the shirt you want with just a glance.

In an automation project, the messy clothes are the methods and classes. Without a good wardrobe (design pattern), the code would be a mess like the clothes, and it would be difficult to read or maintain your project.

Page Object (PO) is the wardrobe that helps keep the code organized (readable and maintainable). With readable and maintainable scripts, the automation case will be much more robust, and it helps save effort on code understanding and maintenance.

Page Factory is a class (provided by Selenium WebDriver) to implement the Page Object Model (POM). It provides annotations instead of FindElement and FindElements to initialize elements, making them descriptive and readable.

What are the advantages of using Page Factory?

  • Clean code
    The defined web element is separated from the methods to make the class clean and tidy in a PO class.
  • Readable and descriptive
    A web element is declared as a member variable (known as Object Field), and the field annotation is used to describe the element name, type, and location. In this way, we can easily identify any defined web element by its annotations like name, type, etc.
  • Maintainable
    The defined web element can be used without re-definition anywhere in the PO class and subclasses. This means that a specific web element may be used many times but is defined at only one place. This means maintaining it at one place will affect all places.

 

For example:
Here is a well-designed PO class. You can easily know what it is doing if you know the basics of coding.

Design pattern in test automation – Page object – login web pagePic 2-1: Login Page



Pic 2-1 is a login web page with 3 web elements: username input box, password input box, and a login button.

Now, let’s look at the next image:

Design pattern in test automation – Page object class for login web page Pic 2-2: PO class for the Login page

Pic 2-2 is the PO class for the login page. Web elements on the login web page (Pic 2-1) are defined as member variables with readable annotations (known as fields).

What does Page Factory do?

In the example (Pic 2-2), 3 WebElement objects (txtUserName, txtPassword, btnLogin) are defined as member variables without being initialized in the PO class. These objects are called directly by the public member method login. Then we can log in to the website by a simple demo (Pic 3-1).

 

Design pattern in test automation – Page factory for login web page Pic 3-1: Test Login

 

Based on basic knowledge of Java, “NullPointerException” should be thrown out if a variable is not initialized. It seems the WebElement objects are not initialized in the PO class. How does the demo (Pic 3-1) work as expected, without any error?

If the variable txtUserName is null, why not throw NullPointerException?
Something must initialize it silently.

Let us look back into the PO class (Pic 2-2) again. A static method in PageFactory class is called by its construction method. This static method is how Page Factory works on a PO class. Page Factory initializes the declared field (WebElement object) in a PO class (Pic 3-2).

Design pattern in test automation – Page factory for login web page

Pic 3-2: Page Factory initializes WebElement object

How does Page Factory work?

We know that Page Factory initializes a declared variable of the WebElement object so that these defined WebElement objects can be called directly in the PO class and subclasses.

Page Factory is helpful but not enough. A live project often requires additional operations to initialize a WebElement object. Here are some examples:

  • State verification
    To get the WebElement with an expected state. E.g., before clicking a button, the button should be visible and enabled.
  • Time out (synchronization)
    Selenium has a configuration of implicitlyWait to ensure that a specific web element appears within a global time out. But if it is not specific, it makes no sense to use the largest wait configuration for all elements.

The test code will become messy if many additional operations are added inline. Is there a way to avoid this situation? Can we get a well-prepared WebElement after Page Factory initializes it? To be able to that, it is necessary to understand how Page Factory works.

Page Factory converts and assigns the object WebElement as follows: (the sequences marked in the flow chart are mapped to the key classes in Pic 4-2).

  • Page Factory defines the WebElement and its annotation as an object Field (Pic 4-1) in the PO class.
  • Object Field is divided into two objects, object Annotation and the non-initialized object WebElement.
  • Object Annotation (@FindBy) generates the object By in the Annotations class (Pic 4-1, flow ①),
  • The object By generates the object ElementLocator in the DefaultElementLocator class (Pic 4-1, flow ②) and object ElementLocator is converted to an initialized object WebElement by DefaultFieldDecorator class (Pic 4-1, flow ③).
  • At last, the initialized object WebElement that ElementLocator generates is assigned to the non-initialized WebElement, which is separated from object Field (Pic 4-1, flow ④).
  • The PO class will be ready after all declared fields go through the same process.

Page factory flow chart – test automationPic 4-1: Page Factory - flow chart

 

  1. org.openqa.selenium.support.pagefactory.Annotations
  2. org.openqa.selenium.support.pagefactory.DefaultElementLocator
  3. org.openqa.selenium.support.pagefactory.DefaultFieldDecorator
  4. org.openqa.selenium.support.PageFactory

Pic 4-2: Page Factory – key classes for the flow chart

 

Let’s dive into the code details to see how the objects described in the flow chart are generated.

Object Annotation -> object By

  1. org.openqa.selenium.support.pagefactory.Annotations

    Method: buildByFromShortFindBy, buildByFromLongFindBy

    Input: Object Annotation, e.g. @FindBy(locateType = StringLocator)

    Output: Object By

    Page factory flow chart – Object annotation – object byBased on the input annotation, the method will go through all the Locators to find out the non-empty string (Defined locateType in the annotation) and then build the object By, based on the annotation locate type and value.

     

    Object By -> object ElementLocator

  2. org.openqa.selenium.support.pagefactory.DefaultElementLocator

    Method: DefaultElementLocator (construction method)

    Input: Object By, object SearchContext (context, e.g. initialized WebDriver), Boolean variable shoudCache (optional annotation, not include in this article)

    Output: Object ElementLocator

    Page factory flow chart – object by – Object element locator

     

    Object ElementLocator -> object FieldDecorator

  3. org.openqa.selenium.support.pagefactory.DefaultFieldDecorator

    Method: proxyForLocator, proxyForListLocator

    Input: ClassLoader for PO class, object ElementLocator

    Output: proxy for object WebElement

    Page factory flow chart – Object element locator – object Field Decorator

    The instance creation of WebElement or List<WebElement> is using a proxy. Each proxy has its invocationHandler.

    Selenium comprises two invocationHandlers:

    • LocatingElementHandler is for object WebElement
    • LocatingElementListHandler is for object List<WebElement>

    By using a proxy, the object WebElement is created regardless of whether the element exists or not. When a method of object WebElement is called, it automatically searches for the element. In this case, the case execution will be more stable and help avoid exceptions such as the StaleElementReferenceException.

     

    Object FieldDecorator -> Initialized WebElement

  4. org.openqa.selenium.support.PageFactory

    Method: proxyFields

    Input: Object FieldDecorator, PO object, PO class

    Output: All the defined object WebElement in the PO class is initialized and assigned with a proxy object

    Page factory flow chart - object Field Decorator – initialized web element
    Method ProxyFields goes through all the Field objects (Defined object WebElement) within a PO class and the superclasses by a for loop. Each object field uses a method decorator (Method in object FieldDecorator) to get the initialized object WebElement.

Bottom line

A healthy framework should be clear and well-designed in framework layer and logic. It should also be readable and maintainable in a page object class.

There are always some complex web pages or some common additional operations that must be performed on all WebElement objects. Familiarity with the Page Factory mechanism and appropriate customizations can avoid messy definitions and make the PO classes much tidier and readable.

Customized Page Factory also improves the velocity of test automation in many Nagarro projects. In one of our projects, only six engineers covered the execution and maintenance work of 20,000 scripts that run daily.

Page Factory is one of the best practices to build automation frameworks, especially for enterprise-level, complex web applications. Are you looking to develop automation frameworks based on Page Factory? Our experts can help you! Explore our offerings and get in touch with us.

Author
Coby Guo
Coby Guo
connect