Page Factory Based Selenium Automation Framework

Introduction

We have all are heard about the Page Object Model (POM). This article will provide you an introduction to "Page Factory" and its implementation in Selenium using Java.

Page Factory is an builtin Page Object Model concept for Selenium WebDriver but it is very optimized.

Background

Page Factory can be used in any kind of framework such as Data Driven, Modular or Keyword Driven. Page Factory gives more focus on how the code is being structured to get the best benefit out of it.

Advantages of Page Factory

  1. Whenever we use a WebElement it will find it again so you shouldn't see StaleElementExceptions.
  2. On PageFactory Initialization the proxies are configured, but the WebElements are not found at that point. So we won't get NoSuchElementException.

We will see more on how to initialize Page Factory.

Architecture

There are various components on which any framework structure depends on, here we will see the Page Factory automation architecture in detail.

Architecture Design

Architecture Design


Architecture Components

Test Class

In the Test Class we will write an actual Selenium test script. Here we call a Page Action and specified actions to be done on Web Pages. For each page we can write our own test class for better code readability. We can write test cases in @Test annotation.

Page Action Class

In the Page Action Class, we can write all the web page's actions as in the pages and functionality. Under the Page Action component, for each page in the application we have a corresponding Page class.

The Page Action class will call the Page Factory class, the page Factory returns the WebElmenet of the web page and the Page action class has the Page Method that performs an action on those WebElements.

It's very easy to jump on another Page Action class to call any reusable Page Action Method.

Page Factory Class

The Page Factory class is nothing but an Object Repository in another term. For each web page it has its own Page Object Definitions. Each web element should be uniquely identified and should be defined at the class level. We will use FindBy annotation and will define the web element so that we can perform actions on them.

Reports/DB Connection Class

Here we can write our own business layers, Report Structure, DBConnection and so on. This Component is usually called from the Page Action class under the Page Action Method.

Environment Required

  1. Java
  2. Eclipse IDE
  3. Selenium Webdriver
  4. TestNG

Eclipse IDE: It's an Integrated Development Environment for many langauges including Java.

Selenium WebDriver: Selenium is an open-source testing framework. The Selenium WebDriver supports most programming languages, like C#, Java, Perl, Python and so on.

TestNG: It is a testing framework inspired from Junit. We have extended a new annotation in TestNG.

Framework

Framework

Framework Structure in Detail

Automation Projects

Assume we are working on multiple Projects/Modules and there is a requirement to automate those modules then in this source folder we have various projects and modules listed.

With this it is easy to make your own Test Suites for a specific project or module. We can write our own initialization script to load all components related to any specific module or project. In the preceding you see Automation.Project.Google for the Google Gmail project. You can add your own projects here.

Automation Framework

In the Automation Framework source folder, we add the Browser, WebElement, Component Functions and other common functions that we use later on in our framework.

Automation Page Factory

The Automation Page Factory source folder is where we have all the object repositories as in modules and projects. In the preceding example you can see PageObject.Login.java for the Google project. We can define more page objects for each web page under the Google project.

Here is the code snippet for how we define the Page Factory.

  1. package automation.PageFactory.Google;  
  2. import org.openqa.selenium.WebDriver;  
  3. import org.openqa.selenium.WebElement;  
  4. import org.openqa.selenium.support.FindBy;  
  5. import org.openqa.selenium.support.PageFactory;  
  6. public class PageObjects_Login {  
  7.     Code Here  
  8. }  
To write the Page Factory code we need to import org.openqa.selenium.support.PageFactory that allows us to use the implementation of the Page Factory.

You can initialize the elements within the constructor of the PageObject (PO) by taking advantage of the "this" keyword to refer to the current class instance, like so:
  1. import org.openqa.selenium.support.PageFactory;  
  2. public PageObjects_Login(WebDriver driver) {  
  3.     this.driver = driver;  
  4.     //This initElements method will create all WebElements  
  5.     PageFactory.initElements(driver, this);  
  6. }  
Additionally, using the PageFactory class, we use annotations of @FindBy to find the WebElement. @FindBy can accept partialLinkText , name, xpath , tagName, id, linkText , CSS and className as attributes.

Here is the code snippet for @FindBy:
  1. @FindBy(xpath=".//*[@id='Email']")   
  2. public WebElement gmailUserIDWebEdit;  
  3.   
  4. @FindBy(id="next")  
  5. public WebElement gmailNextButton;  
  6.   
  7. @FindBy(id="Passwd")  
  8. public WebElement gmailPasswordWebEdit;  
Always use a meaningful name for any WebElement.

Automation Page Action

A Page Action is where we have all our Page Factory calls and Page Action Methods. We have a separate page action for each web page for code reusability.

Here we call respective Page Factory WebElements by creating an instance of a Page Factory class:
  1. package automation.PageActions.Google;  
  2. import java.util.NoSuchElementException;  
  3.   
  4. import automation.PageFactory.Google.PageObjects_Login;  
  5. import org.openqa.selenium.WebDriver;  
  6.   
  7. public class PageActions_Login {  
  8.     WebDriver driver;  
  9.     PageObjects_Login po; // Create Instance to Page Factory class  
  10.     public PageActions_Login(WebDriver driver) {  
  11.         this.driver = driver; // set webDriver for current Page Action  
  12.     }  
  13. }  
In the preceding code snippet in the Page Action class constructor, we set the WebDriver for the current Page Action.

We can write our custom Page Action method to perform an action on Web Elements.

The following is a snippet for entering UserID on a Gmail site.
  1. public void enterPassword(String searchText) {  
  2.     po = new PageObjects_Login(driver);  
  3.     if (po.gmailPasswordWebEdit != null) {  
  4.         try {  
  5.             po.gmailPasswordWebEdit.sendKeys(searchText);  
  6.         } catch (NoSuchElementException e) {  
  7.             // TODO Auto-generated catch block  
  8.             System.out.println("Exception message" + e.getMessage());  
  9.         }  
  10.     }  
  11. }  
Automation Test

In the Automation Test source folder we have a Test class with TestNG test cases.

Here we create an instance of Page Action and call the Page Action method. We just pass a WebDriver instance to the Page Action. 
  1. public class Test_Login {  
  2.   
  3.     WebDriver driver;  
  4.     PageActions_Login actionLogin;  
  5.   
  6.     @BeforeTest  
  7.     public void setup() {  
  8.         driver = new FirefoxDriver();  
  9.         driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);  
  10.         driver.get("http://gmail.com/");  
  11.     }@Test(priority = 0) // Try to sign with Invalid Password   
  12.     public void SignIntoGMailInvalidPassword() {  
  13.         actionLogin = new PageActions_Login(driver);  
  14.         actionLogin.enterUserIDPassword("upadhyay40""xyz");  
  15.         String loginPageTitle = actionLogin.getWrongPasswordTextMessage();  
  16.         Assert.assertTrue(loginPageTitle.contains("The email and password you entered don't match."));  
  17.     }  
In this we use @Test annotation to create TestNG test cases, we call the Page Action method from the test method.

Automation Report

Here we wrote our custom report for a better understanding after our test run.

In the failed case screenshot, after any test case failed it writes a result with a screen shot.

In the graphical report, we can use ReportNG, Velocity and the guice plugin with TestNG.

Implementations of the ITestListener interface are designed for real-time reporting, while implementations of the IReporter interface are intended to generate reports after the suite run is finished.

Implementing an instance of IReporter and the generateReport(List<ISuite> suites, String outputDirectory) method should allow you to look at the test results and create an HTML report.

Automation Business Layer

All the main logical operations are processed in the Automation Business layer. Coordinating the input from the user interface and the data from the database, an Automation Business layer assumes its importance in any software application.