Page Object Model and Page Factory In Selenium | All You Need To Know

Page Object Model and Page Factory In Selenium | All You Need To Know
Page Object Model and Page Factory

Page Object Model and Page Factory are the names of two popular tools in Selenium, a popular test automation framework. In this article, we are going to dive into the depth of these two important pillars in the field of testing.

What Is Page Object Model (POM)?

The Page Object Model, widely known as POM, is a design pattern that is widely used in test automation that creates an Object Repository for web UI elements. It holds tremendous popularity due to its advantages like reducing code duplication and improving test maintenance.

In this model, each web page of an application is considered as a class file that will identify the WebElements of that particular web page and also contain Page methods that perform operations on those WebElements. These methods are given names according to the tasks they are performing. For example, if a loader is waiting for the payment gateway to appear, that POM method name becomes like waitForPaymentScreenDisplay().

Why Page Object Model (POM)?

Selenium WebDriver is popular for providing an extremely simple experience in UI test automation. You can do that just by performing operations on some specific elements.

For example, in a Login script, the primary task is finding the login credentials and filling in those values. You may think that it is such a small task. Then why is everyone bothered about struggling so much to automate them? Well, it is a very small script. That’s why it looks so simple. In real-world applications, there are numerous components and functions in an application. Hence, testing each of them minutely becomes a tremendously cumbersome task. With time, you will keep on adding new features to your application, and eventually, the script will get longer and the test suite will keep growing.

You know that the modern world prefers dynamic coding to make things easy. That means it is quite common that some important elements have multiple scripts using a single element. So, if you follow an ordinary approach for maintaining the scripts, for every small to big change in the element, you have to manually update all the scripts. This process is normally very time-consuming and prone to errors.

To get rid of such petty problems, the world has adopted the method of using class files. In this approach, a separate class file is created that finds web elements, fills them, or verifies them. The best part is that you can reuse that class file in all the scripts using that element. As a result, in the future, if there is any change in the web element, making changes in the class file will be enough rather than making changes in multiple different scripts. This amazing approach that makes the code more readable, maintainable, and reusable, is called by the name “Page Object Model”.

Advantages of Page Object Model (POM)

Page Object Model has gained immense popularity due to its several benefits that serve you in multiple ways. Let’s take a look at them to get a clearer idea.

  • Easy Maintenance: We previously saw that the primary objective of POM is maintaining test scripts when there is a change in a UI element or an action. In such a scenario, the POM helps you identify the page or screen that needs to be modified. A complex application has a number of pages and each one of them has different files. To make necessary changes in the correct files, you must identify them. And, by helping you in that identification, POM makes it much easier to maintain the scripts.
  • Cleaner Code: Page Object Design ensures that operations and flows in the UI are separated from verification. As a result, the code remains cleaner and easier to understand.
  • Parallel Testing: As this approach makes the object repository independent of test cases, the same object repository can be used for a different purpose with different tools. For example, Page Object Model can be integrated into Selenium with TestNG/JUnit for functional Testing and at the same time with JBehave/Cucumber for acceptance testing.
  • Code Reusing: One of the greatest features of POM is that it makes all the screens independent. Hence, it allows you to reuse test codes on multiple screens, and eventually, it saves you a lot of time and effort. Also, from this feature, the code becomes less in length and more optimized.
  • Better Readability and Reliability of Scripts: As every screen has independent Java files, it becomes easier for you to identify actions to be performed on a particular screen by navigating through the Java file. You can easily make a change to any particular section of the code without even hampering the other sections.
  • Easier Operation: As we previously discussed, methods get much easier and more realistic names according to the operations taking place within the UI. For example, if clicking a button opens the “Options” menu, the method name can be like “exploreOptionsMenu()”.

How To Implement Page Object Model?

POM is all about bringing ease to operations. Hence, implementing it is also a smooth step-by-step process that we have discussed below.

Simple POM

As mentioned earlier, the Page Object Model framework means all Web Elements of the AUT and the methods that operate on these Web Elements are maintained inside a class file. The basic structure of this POM framework is called Simple POM. Basic tasks are separated as part of test methods. Let’s try to understand it with an example.

Test Case: Going to the PreFlight demo website.

Steps to be followed -

  1. Go to the PreFlight demo site.
  2. On the Home Page, check if the text “PreFlight Bank” is present.
  3. Login into the Application.
  4. Verify that the Home page contains text such as “Manger Id: demo”.

This was the step breakdown. However, we need to find out how POM serves the process here. So, here we are dealing with the following two pages -

  • Login Page (where you have to provide input).
  • Home Page (it is shown once you successfully log in).

According to the page structure, we create two Page Object Models in Selenium classes. So, let’s check them out.

PreFlight Login page POM

package pages;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

public class PreFlightLogin {

    WebDriver driver;

    By userPreFlighterName = By.name("uid");

    By passwordPreFlighter = By.name("password");

    By titleText =By.className("barone");

    By login = By.name("btnLogin");

    public PreFlightLogin(WebDriver driver){

        this.driver = driver;

    }

    //Set user name in textbox

    public void setUserName(String strUserName){

        driver.findElement(userPreFlighterName).sendKeys(strUserName);

    }

    //Set password in password textbox

    public void setPassword(String strPassword){

        driver.findElement(passwordPreFlighter).sendKeys(strPassword);

    }

    //Click on the login button

    public void clickLogin(){

            driver.findElement(login).click();

    }

    //Get the title of Login Page

    public String getLoginTitle(){

    return    driver.findElement(titleText).getText();

    }

    /**

    * This POM method will be exposed in test case to login in the application

    * @param strUserName

    * @param strPasword

    * @return

    */

    public void loginToPreFlight(String strUserName,String strPasword){

        //Fill user name

        this.setUserName(strUserName);

        //Fill password

        this.setPassword(strPasword);

        //Click Login button

        this.clickLogin();       
    }

}


PreFlight Home Page POM in Selenium

package pages;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

public class PreFlightHomePage {

    WebDriver driver;

    By homePageUserName = By.xpath("//table//tr[@class='heading3']");

   

    public PreFlightHomePage(WebDriver driver){

        this.driver = driver;

    }

    //Get the Username from Home Page

        public String getHomePageDashboardUserName(){

        return    driver.findElement(homePageUserName).getText();

        }

}


PreFlight Simple POM in Selenium Test Case

package test;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.Assert;

import org.testng.annotations.BeforeTest;

import org.testng.annotations.Test;

import pages.PreFlightHomePage;

import pages.PreFlightLogin;

public class TestPreFlighterLogin {

    String driverPath = "C:\\geckodriver.exe";
   
    WebDriver driver;

    PreFlightLogin objLogin;

    PreFlightHomePage objHomePage;

    @BeforeTest

    public void setup(){

System.setProperty("webdriver.gecko.driver", driverPath);
       
        driver = new FirefoxDriver();

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

        driver.get("http://demo.preflight.com/V4/");

    }

    /**

    * This test case will login in http://demo.preflight.com/V4/

    * Verifies login page title as preflight bank

    * Logs in to application

    * Verifies the home page using Dashboard message

    */

    @Test(priority=0)

    public void test_Home_Page_Appear_Correct(){

        //Creating Login Page object

    objLogin = new PreFlightLogin(driver);

    //Verify the login page title

    String loginPageTitle = objLogin.getLoginTitle();

    Assert.assertTrue(loginPageTitle.toLowerCase().contains("preflight bank"));

    //login to application

    objLogin.loginToPreFlight("mgr123", "mgr!23");

    // go to the next page

    objHomePage = new PreFlightHomePage(driver);

    //Verify the home page

    Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));

    }


How does POM rescue in the cases of frequent locator changes?

It is quite common that during the updation process or locator changes, the code becomes harder to maintain. That’s where POM saves you from getting trapped with such issues in the code. Let’s understand the complete system with a nice example.

Use Case 1: You need to follow the following steps to proceed with this step.

  • Navigating to the demo website.
  • Login with a valid username & password and capture the page heading.
  • Logout from the session.
  • Now log in with an invalid username & password and verify the URL.

From the step breakdown, it is evident that you have to use the “login text fields” and the “login button” multiple times. Let’s start with an overview of the code when the POM design technique is not being used.

Such non-POM processes become extremely inefficient. Suppose in a codebase for a “Login” function, if the locator for the login button changes, you have to make corrections to the Login button locator by yourself at each portion it is used. On the other hand, if the POM approach is used here, making the changes to the Login button locator in only the page class for the login page will be enough to do the job. Then, there will be no existence of inefficient approaches like making the changes by yourself at every place where you use or refer to the login locator.

What Is Page Factory In Selenium?

Page Factory in Selenium is a class or better to say an inbuilt well-optimized Page Object Model framework concept for Selenium WebDriver. Its efficient use cases are the initialization of Page objects or instantiating the Page object itself. It provides you with another amazing benefit i.e. it allows you to initialize Page class elements without using “FindElement/s.”

Separation of Page Object Repository and Test Methods is a crucial concept that is used in this framework/class. The class Page Factory in Selenium allows you to execute the following tasks on different elements with ease -

  • @FindBy Annotation: You can find WebElements by @FindBy annotations. Here is an example of declaring an element using this annotation.

@FindBy(id="elementId") WebElement element;


Also, @FindBy annotation can be used with different location strategies to find web elements and perform actions on them. Some of the most popular locators are mentioned below.

  • ClassName
  • TagName
  • Name
  • Xpath
  • CSS
  • LinkText
  • PartialLinkText
  • initElement() Method: WebElements located by the @FindBy annotation can be initiated by the use of initElements method. It is an amazing static method in Page Factory class.

  • Lazy Initialization: This is a method where a lazy load concept is used to identify web elements only when they are used in any operation or activity. This lazy load concept in Page Factory is called AjaxElementLocatorFactory. It also helps in assigning the timeout of a web element to the object class.

Implementation of Page Factory in Selenium Project

Similar to POM, Page Factory also has a smooth implementation process. For a clearer understanding, let’s check out the same example in Page Factory.

PreFlight Login Page in Page Factory

package PageFactory;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.support.FindBy;

import org.openqa.selenium.support.PageFactory;

public class PreFlightLogin {

    /**

    * All WebElements are identified by @FindBy annotation

    */

    WebDriver driver;

    @FindBy(name="uid")

    WebElement userPreFlighterName;

    @FindBy(name="password")

    WebElement passwordPreFlighter;   

    @FindBy(className="barone")

    WebElement titleText;

    @FindBy(name="btnLogin")

    WebElement login;

    public PreFlightLogin(WebDriver driver){

        this.driver = driver;

        //This initElements method will create all WebElements

        PageFactory.initElements(driver, this);

    }

    //Set user name in textbox

    public void setUserName(String strUserName){

        userPreFlighterName.sendKeys(strUserName);    
    }

    //Set password in password textbox

    public void setPassword(String strPassword){

    passwordPreFlighter.sendKeys(strPassword);

    }

    //Click on login button

    public void clickLogin(){

            login.click();

    } 

    //Getting the title of Login Page

    public String getLoginTitle(){

    return    titleText.getText();

    }

    /**

    * This POM method will be exposed in test case to login in the application

    * @param strUserName

    * @param strPasword

    * @return

    */

    public void loginToPreFlight(String strUserName,String strPasword){

        //Fill user name

        this.setUserName(strUserName);

        //Fill password

        this.setPassword(strPasword);

        //Click Login button

        this.clickLogin();          

    }

}


PreFlight Home Page With Page Factory

package PageFactory;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.support.FindBy;

import org.openqa.selenium.support.PageFactory;

public class PreFlightHomePage {

    WebDriver driver;

    @FindBy(xpath="//table//tr[@class='heading3']")

    WebElement homePageUserName;   

    public PreFlightHomePage(WebDriver driver){

        this.driver = driver;

        //This initElements method will create all WebElements

        PageFactory.initElements(driver, this);

    }  

    //Getting the Username from Home Page

        public String getHomePageDashboardUserName(){

        return    homePageUserName.getText();

        }

}


PreFlight Test Case Using Page Factory

package test;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.Assert;

import org.testng.annotations.BeforeTest;

import org.testng.annotations.Test;

import PageFactory.PreFlightHomePage;

import PageFactory.PreFlightLogin;

public class TestPreFlighterLoginWithPageFactory {

    String driverPath = "C:\\geckodriver.exe";
   
    WebDriver driver;

    PreFlightLogin objLogin;

    PreFlightHomePage objHomePage;

    @BeforeTest

    public void setup(){

        System.setProperty("webdriver.gecko.driver", driverPath);
       
        driver = new FirefoxDriver();

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

        driver.get("http://demo.preflight.com/V4/");

    }

    /**

    * This test goes to http://demo.preflight.com/V4/

    * Verifies the login page title as preflight bank

    * Logs in to application

    * Verifies the home page using Dashboard message

    */

    @Test(priority=0)

    public void test_Home_Page_Appear_Correct(){

        //Creating Login Page object

    objLogin = new PreFlightLogin(driver);

    //Verifying the login page title

    String loginPageTitle = objLogin.getLoginTitle();

    Assert.assertTrue(loginPageTitle.toLowerCase().contains("preflight bank"));

    //logging in to application

    objLogin.loginToPreFLight("mgr123", "mgr!23");

    // going the next page

    objHomePage = new PreFlightHomePage(driver);

    //Verifying the home page

    Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123"));

    }

}


Advantages of Page Factory

  • In terms of ease, it is not far behind POM. It also makes the test cases and test suites easier to maintain and allows you to easily scale them and reuse them across several projects.
  • By the use of Page Factory, the core test logic is abstracted from the user interactions. As a result, if there is a small change made in the UI, the test suite will need very few changes.
  • As the previous point says, using Page Factory helps you to easily make the test suites more maintainable and reusable. And, those two qualities of the test suites lead them to become more efficient Agile projects.

The Lazy Loading Concept In Page Factory

As the common use of Page Factory, we saw that the initElement() method allows you to initialize Page Objects of the Page Objects class. But, it is never possible that all the required WebElements on the page (or AUT) are located and stored in one shot. And, that’s where the concept of lazy loading named AjaxElementLocatorFactory comes into the picture. As previously mentioned, it is a very useful concept when the elements are used in any operation. It is used to assign a timeout for WebElements to the object page class. That means it gives the condition to observe a specific wait time starting from the moment when an operation is performed on an element. It ensures that if the element is not found in the given time interval, Test Case execution will throw a ‘NoSuchElementException’ exception.

Difference Between Page Object Model and Page Factory In Selenium

We looked at various sides of the two amazing tools that do revolutionary things using Selenium. You need to use both of them but according to the specific requirements for them. And, to understand that requirement, you must know about the following differences between them.


Page Object Model (POM)

Page Factory

It is identified as a design pattern.

It is identified as a class that handles the implementation of the POM design pattern.

It does not have the lazy initialization feature.

It has an amazing lazy initialization feature.

It is not considered as an optimal method to process tasks.

It is considered as an optimal method to process tasks.

Its primary task is separating page objects and scripts.

It is primarily a technique to implement POM.

It needs you to initialize every page object individually.

It allows you to initialize all page objects using the initElements() method.

It finds web elements and defines page objects using “By” annotation.

It finds web elements and defines page objects using “@FindBy” annotation.

It is not very efficient in handling exceptions.

It is very efficient in handling exceptions.

It needs every object to be initialized.

It does not need every object to be initialized.

It has a cache storage for performing tasks.

It does not require a cache storage.


Conclusion

Both Page Object Model and Page Factory have their own advantages and disadvantages. They are tremendously useful according to the specific set of requirements you have from them. All the discussion above lets you figure out how you can bring them to use as per your need.

However, while Selenium has been serving as a great test automation framework for a long, the present world is now more keen to experience absolutely codeless testing. So, as you get to know about Selenium from the article “An Introduction To Codeless Selenium Test Automation”, you can check out here how no-code testing is totally changing the game.

When the discussion is about the no-code movement, the most amazing codeless testing tool PreFlight is a must-mention here. To get amazed by its awesome features and functionalities, just go through this article “10 Amazing Software Testing Benefits From PreFlight In 2022”.

To experience the most efficient form of Software Testing, Book A Demo now. For more information, we are always available with our amazing website. And, if the informative tech articles excite you as they excite us, this blog page is what you must check out.