Complete Page Object Model Framework -2021

In this tutorial, we will learn about the Page Object Model, and also we will design and develop the Page Object Model framework from scratch. 

We had discussed all the types of framework in Selenium, including Page Object Model , here we would go through in-depth.

Page Object Model Framework
Page Object Model Framework Development

We will design and develop the below features .

What is Page Object Model Framework design in Selenium  

Page Object Model is a Design Model for building Selenium test Automation, where we distribute our whole Application under test into small pages (sometimes a webpage is considered as a page, and sometimes a subpart of a Webpage is also considered as a Page ). Each of these pages is represented as a Java class, and the functionalities of the pages are written as different methods in the respective page’s Java class.

Let’s say you have a Gmail application which you will automate; hence the Gmail login page is there where you have few major functionalities such as login, create an account, etc.

Here we will create a java class as GmailLoginPage, and we will write methods named as performLogin() , createUserAccount, etc. 

Let’s say once you are logged in to your Gmail account, you have many features like inbox, sent items, trash, etc. Now here, for each module, you create a Java class and keep their functionalities as Java methods inside respective java classes. 

Why Page Object Model

Page Object Model is a very robust and advanced framework design model where you can take care of the below areas : 

  • Security of web pages automation codebase (each webpage functionalities and code is not exposed to other webpage or java class)
  • Reusable, i.e., you can call the respective page method without writing it in “n” number of places in your framework.
  • The Locator of each of the page resides in different locations (page level interfaces or by using pagefactory, so in case of any new locators for that page or change in locator you can simply go to the respective page locators area and change it, and it will be reflected in the calling methods where ever the locators are being called)
  • Easy debugging due to the above features
  • Easily maintainable.
  • Scalable: You can integrate a wide range of tools /clients along with your Page Object model framework and enhance and scale your page object model framework to automate supercritical use cases as well. 

Hybrid Page Object Model Framework Structure

In the previous tutorial, we understood the hybrid Page Object Model, and now we will design and develop a framework.

The architecture of the Page Object Model framework

We can simply create a maven project and incorporate the dependencies in POM.xml file thats required for the framework initially which looks like this one : 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>demo</groupId>
	<artifactId>DemoAutomation</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>DemoAutomation</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.0</version>
				<configuration>
					<source>7</source>
					<target>7</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.4.2</version>
				<configuration>
					<suiteXmlFiles>
						<suiteXmlFile>testNg.xml</suiteXmlFile>
					</suiteXmlFiles>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<reporting>
		<plugins>
			<plugin>
				<groupId>org.reportyng</groupId>
				<artifactId>reporty-ng</artifactId>
				<version>1.2</version>
				<configuration>
				    <outputdir>/target/testng-xslt-report</outputdir>
				    <sorttestcaselinks>true</sorttestcaselinks>
			            <testdetailsfilter>FAIL,SKIP,PASS,CONF,BY_CLASS</testdetailsfilter>
				    <showruntimetotals>true</showruntimetotals>
				</configuration>
			</plugin>
		</plugins>
	</reporting>
	<dependencies>
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-server</artifactId>
			<version>2.53.0</version>
		</dependency>
		<dependency>
			<groupId>org.testng</groupId>
			<artifactId>testng</artifactId>
			<version>6.8.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.8</version>
		</dependency>

		<dependency>
			<groupId>com.googlecode.json-simple</groupId>
			<artifactId>json-simple</artifactId>
			<version>1.1</version>
		</dependency>

		<dependency>
			<groupId>net.sourceforge.jexcelapi</groupId>
			<artifactId>jxl</artifactId>
			<version>2.6</version>
		</dependency>
	</dependencies>
</project>

After that, we will build small modules and utilities, where we have attached this snapshot below just to provide high-level insights/view. We will build utilities one by one. 

Selenium Page Object Model Framework Structure

Here are the below modules that we will develop; we have provided the code snippet for the same : 

DriverUtils – Page Object Model Framework

This module provides all the utilities and support to work with the various browsers (Chrome, Firefox, etc.).This utility is based on the Factory design pattern, as we discussed in the previous tutorial here.

package com.base.driverUtils;

import org.openqa.selenium.WebDriver;

public interface IDriver {

  public WebDriver init(String browserName);
}

Localdriver implementation, which will execute locally with Selenium Webdriver :

package com.base.driverUtils;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public class LocalDriver implements IDriver {

  public WebDriver init(String browserName) {
     switch (browserName) {
     case "firefox":
        return new FirefoxDriver();

     case "chrome":
        System.setProperty("webdriver.chrome.driver",
              "..\\DummyAutomation\\DriverExe\\chromedriver.exe");
        return new ChromeDriver();

     case "ie":
        System.setProperty("webdriver.ie.driver",
              "..\\DummyAutomation\\DriverExe\\IEDriverServer.exe");
        return new InternetExplorerDriver();
     default:
        return new FirefoxDriver();
     }
  }

}

Remote Webdriver: To work with a remote webdriver (such as Selenium Grid), you need a remote reference of the browser driver, which goes like : 

package com.base.driverUtils;

import java.net.MalformedURLException;
import java.net.URL;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

public class RemoteDriver implements IDriver {

  DesiredCapabilities caps;
  String remoteHuburl;

  @Override
  public WebDriver init(String browserName) {
     switch (browserName) {
     case "firefox":
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.firefox());
        } catch (MalformedURLException e2) {
           // TODO Auto-generated catch block
           e2.printStackTrace();
        }
     case "chrome":
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.chrome());
        } catch (MalformedURLException e1) {
           // TODO Auto-generated catch block
           e1.printStackTrace();
        }
     case "ie":
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.internetExplorer());
        } catch (MalformedURLException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
     default:
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.firefox());
        } catch (MalformedURLException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
     }
     return null;
  }
 

}

Factory Driver class: This provides us the driver class (remote/local) object to initiate the browsers of your choice. We will take the type of driver(local or remote) and browser (chrome or firefox etc.) through the configuration file(we have used a properties file to keep the configurations, which we will share shortly )

package com.base.driverUtils;

public class DriverProvider {

  public IDriver getDriver(String typeOfDriverExecution){
     switch(typeOfDriverExecution){
     case "local":
        return new LocalDriver();
     case "remote":
        return new RemoteDriver();
     default :
        return new LocalDriver();
     }
  }
}

Now wherever you require the driver reference, you can simply create the object of the factory class object (DriverProvider in this case) and can initiate the driver browser instance.

Here is the very basic config file; you can create a properties file and store the values like this : 

modeOfExecution=local
browser=chrome
url=http://www.applicationUrl.com/

DataUtils-Page Object Model Framework: 

We have designed the data utilities here as the same Factory design pattern as we did from implementing the driver browser modules.

Here is the below code snippet for the same; in the framework, we have shown Excel utils and properties utils, you can enhance more to support other data utilities like YAML, PDF, etc.: 

The interface here goes like this: 

package com.base.dataUtils;

public interface IDataProvider {

  public Object[][] fetchDataSet(String... dataFileInfo);
  public String fetchData(String... dataFileInfo);
}

Here is the implementation for Excel Data provider

package com.base.dataUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelDataProvider implements IDataProvider {

  FileInputStream fis = null;
  private static XSSFWorkbook workBook = null;
  private static XSSFCell Cell;
  private static XSSFSheet sheet;

  public static String[][] excelDataSet = null;

  @Override
  public Object[][] fetchDataSet(String... dataFileInfo) {
     String excelFilePath = dataFileInfo[0];
     String excelSheetName = dataFileInfo[1];
     File file = new File(excelFilePath);

     try {
        fis = new FileInputStream(file);
     } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     }
     try {
        workBook = new XSSFWorkbook(fis);
     } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     }
     sheet = workBook.getSheet(excelSheetName);
     int ci, cj;
     int rowCount = sheet.getLastRowNum();
     int totalCols = sheet.getRow(0).getPhysicalNumberOfCells();
     excelDataSet = new String[rowCount][totalCols - 1];
     ci = 0;
     for (int i = 1; i <= rowCount; i++, ci++) {
        cj = 0;
        for (int j = 1; j <= totalCols - 1; j++, cj++) {

           try {
              excelDataSet[ci][cj] = getCellData(i, j);
           } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }
        }
     }
     return excelDataSet;

  }

  public static String getCellData(int RowNum, int ColNum) throws Exception {

     try {

        Cell = sheet.getRow(RowNum).getCell(ColNum);

        int dataType = Cell.getCellType();

        if (dataType == 3) {

           return "";

        }

        else if (dataType == XSSFCell.CELL_TYPE_NUMERIC) {
           int i = (int) Cell.getNumericCellValue();
           return Integer.toString(i);
        }

        else {

           String CellData = Cell.getStringCellValue();

           return CellData;

        }
     } catch (Exception e) {

        throw (e);

     }

  }

  @Override
  public String fetchData(String... dataFileInfo) {
     // TODO Auto-generated method stub
     return null;
  }

}

Properties Data provider : 

package com.base.dataUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDataProvider implements IDataProvider {

  FileInputStream fis=null;

  @Override
  public Object[][] fetchDataSet(String... dataFileInfo) {
     // TODO Auto-generated method stub
     return null;
  }

  @Override
  public String fetchData(String... dataFileInfo) {

     String dataValue;
     String pathToFile = dataFileInfo[0];
     String key = dataFileInfo[1];
     Properties properties = new Properties();
     try {
        fis=new FileInputStream(pathToFile);
        properties.load(fis);
     } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     }
     dataValue = properties.getProperty(key);
     return dataValue;
  }

}

The factory class for this data Utilities

package com.base.dataUtils;

public class DataHelperProvider {

  public IDataProvider getDataHelperProvider(String typeOfDataHandler) {
     switch (typeOfDataHandler) {
     case "excel":
        return new ExcelDataProvider();
     case "properties":
        return new PropertiesDataProvider();
     }
     return null;

  }
}

WebAction utilities -Page Object Model Framework

In the utilities, we write all the utilities related to your Web actions like (click, sendkeys, screenshots, etc.), and we can utilize it in Page Methods to perform web actions to achieve the page functionalities as discussed earlier in this tutorial. 

Here is the code snippet for the WebAction Utilities : 

package com.base.webActionHelperUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;


public class WebActionsHelperUtils {

  protected WebDriver driver;

  public WebActionsHelperUtils(WebDriver driver) {

     this.driver = driver;
  }

  public void safeClick(By element) {

     waitForElementToBeClickAble(element, 30);
     driver.findElement(element).click();
  }

  public List<WebElement> getElements(By elements) {
     return driver.findElements(elements);
  }

  public void waitForWebElementsToBeDisplayed(By elements, int timeOuts) {
     WebDriverWait wait = new WebDriverWait(driver, timeOuts);
     wait.until(ExpectedConditions.visibilityOfAllElements(getElements(elements)));
  }

  public void waitForElementToBeClickAble(By element, int timeOutSeconds) {
     WebDriverWait waitForElement = new WebDriverWait(driver, timeOutSeconds);
     waitForElement.until(ExpectedConditions.elementToBeClickable(element));
  }

  public void waitForElementToBeDisplayed(By element, int timeOuts) {
     WebDriverWait wait = new WebDriverWait(driver, timeOuts);
     wait.until(ExpectedConditions.visibilityOfElementLocated(element));
  }

  public void enterTextIntoElement(By element, String textToBeEntered) {
     driver.findElement(element).sendKeys(textToBeEntered);
  }

  public String getText(By element) {
     return driver.findElement(element).getText();

  }

  public String getAttribute(By element, String attribute) {
     return driver.findElement(element).getAttribute(attribute);
  }

  public boolean isSelected(By element) {
     boolean isElementSelected = false;
     if (driver.findElement(element).isSelected() == true) {
        isElementSelected = true;
     }
     return isElementSelected;
  }

  public void clearField(By element) {
     driver.findElement(element).clear();
  }

  public void implicitlyWait(int timeOuts) {
     driver.manage().timeouts().implicitlyWait(timeOuts, TimeUnit.SECONDS);
  }

  public boolean isElementPresent(By element) {
     try {
        driver.findElement(element);
        return true;
     } catch (Exception e) {
        return false;
     }
  }

  public void switchToTab(int indexOfTab) {
     ArrayList<String> tabs = new ArrayList<String>(driver.getWindowHandles());
     driver.switchTo().window(tabs.get(indexOfTab));

  }
}

Page Module utilities-Page Object Model Framework

Like we know, we have to create the Page class and keep the page functionalities in the page methods, so now let’s create the Page Module for the Page Object Model framework : 

Every Page Class again extends the WebAction Utils that we developed just now and implements the Page interfaces, where the page interfaces are nothing but the interfaces to keep the respective page’s Web Elements/locators.

Now Why we need interfaces to store the locators : 

  • We could use any properties/excel file to keep locators from there, but in this approach, we have to fetch the locators every time we intend to use it in the page methods where the time complexity will get increased, so we did not store the locators in files. 
  • We could use the same class(pageclass with page factory implementation with @findBy annotation ), but we did not use this classic Page object Model because storing respective locators in the respective page classes, the code will be unreadable and clumsy, we wanted to separate the locators from the code to maintain clean codebase and maintainability and debugging and reusability also will get increased in this approach.
  • We could store the locators in separate classes, but we did not do so because to call “N” page locators classes, we had to create the “n” number of objects of the locators classed; hence the space complexity will be impacted.

Hence we used separate interfaces for separate page locators to store as by this approach; we solve all the above problem statements, which are time complexity, space complexity, and the clean and maintainable codebase as in interfaces, we don’t have to create objects to access locators.

package com.base.pageModules;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import com.base.commonUtils.JSonHandler;
import com.base.webActionHelperUtils.WebActionsHelperUtils;
import com.page.locatorModules.HomePageLocators;

public class HomePage extends WebActionsHelperUtils implements HomePageLocators {

  JSonHandler jsonHandler = new JSonHandler();

  public HomePage(WebDriver driver) {
     super(driver);
     this.driver = driver;
  }

  public void enterSearchdataToSearchField(String searchData) {

     waitForElementToBeClickAble(SEARCH_BOX, 10);
     enterTextIntoElement(SEARCH_BOX, searchData);

  }

  public void navigatToUrl() {
     driver.get(url);
  }

  public void captureSearchSuggestion(String pathToJsonDataStore, String searchData) {
     List<WebElement> elements = getElements(SUGGESTION_BOX);
     jsonHandler.captureAndWriteJsonData(elements, pathToJsonDataStore, searchData);
  }

  public void genericWait(int timeOuts) {
     implicitlyWait(timeOuts);
  }

  public void clikcOnSelectedElement(String option) {
     int optionSelection = Integer.parseInt(option);
     safeClick(By.xpath("//div[@id='s-separator']/following-sibling::div[" + optionSelection + "]"));
  }

}

Likewise, you can keep on including the page features in the page different Page methods inside the respective page classes. 

Here is how the Page locators interfaces look like : 

package com.page.locatorModules;

import org.openqa.selenium.By;

public interface HomePageLocators {

 
  By SEARCH_BOX=By.id("twotabsearchtextbox");
  By SUGGESTION_BOX=By.xpath("//div[@id='suggestions']/div");
 
}

Now the next segment, you can create a baseSetUp or Basetest where you want to perform the initialization/data loading parts. Also, you could use @beforeTest, @beoforeClass methods in this class itself and use them in your test classes.

BaseSetup Class looks like : 

package com.demo.testS;

import org.openqa.selenium.WebDriver;
import org.testng.annotations.DataProvider;

import com.base.dataUtils.DataHelperProvider;
import com.base.dataUtils.IDataProvider;
import com.base.driverUtils.DriverProvider;

public class BaseSetUp {

	public WebDriver driver;
	DriverProvider browserProvider = new DriverProvider();
	DataHelperProvider datahelperProvider = new DataHelperProvider();
	IDataProvider dataProvider = datahelperProvider.getDataHelperProvider("properties");
	IDataProvider dataProviderExcel = datahelperProvider.getDataHelperProvider("excel");
	public final String configProperties = "..\\DummyAutomation\\TestConfigsData\\config.properties";
	public String url = dataProvider.fetchData(configProperties, "url");
	String modeOfExecution = dataProvider.fetchData(configProperties, "modeOfExecution");
	String browserName = dataProvider.fetchData(configProperties, "browser");
	String pathToJasonDataStore = "..\\DummyAutomation\\ProductJsonData\\";
	String pathToExcelData = "..\\DummyAutomation\\TestConfigsData\\TestData.xlsx";

	public WebDriver getDriver() {
		return driver;
	}

	protected void setDriver() {
		driver = browserProvider.getDriver(modeOfExecution).init(browserName);
	}

	@DataProvider(name = "SearchFunctionality")
	public Object[][] getCityDetails() {
		Object[][] arrayObject = dataProviderExcel.fetchDataSet(pathToExcelData, "DataFeed");
		return arrayObject;
	}
}

Test Classes: As we would be using TestNG here, so you need to write @test method for the test script to be developed, such as : 

Here is the code snippet for the Test Classes  

package com.demo.testS;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.base.pageModules.HomePage;
import com.base.pageModules.SearchPage;

public class DemoTest extends BaseSetUp {

  HomePage homePage;
  SearchPage searchPage;

  @BeforeMethod
  public void setUpTest() {
     setDriver();
     homePage = new HomePage(driver);
     searchPage = new SearchPage(driver);
     homePage.navigatToUrl();
  }

  @Test(dataProvider = "SearchFunctionality")
  public void search(String searchData, String selectOption) {
     homePage.enterSearchdataToSearchField(searchData);
     homePage.genericWait(5);
     homePage.captureSearchSuggestion(pathToJasonDataStore, searchData);
     homePage.clikcOnSelectedElement(selectOption);
     searchPage.clickOnFirstProduct();
     searchPage.switchToProductSpecificPage();
     searchPage.captureProductData(pathToJasonDataStore, searchData);

  }

  @AfterMethod
  public void tearDown() {
     if (driver != null) {
        driver.quit();
     }
  }

}

TestNgXML file -Page Object Model framework

You would need to define an XML class for the testng.xml, which basically a unit test framework and controls the flow of your automation; you can mention the test classes there themselves.

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="test-parameter" parallel="tests" thread-count="3">

<test name="DemoAutomation_TarGet">
<classes>
<class name="com.demo.testS.DemoTest"></class>

</classes>
</test>
</suite>

So with these activities, your basic Page Object Model framework should be ready now. If you want to Achieve the advanced version of your framework, then you could incorporate these below areas : 

Reporting Feature-Page Object Model Framework

You can use any reporting feature available like allure, extentreport, TestNG report, or advance reporting by using ELK stack, etc. 

Just to keep the simplicity, we are showing here the reporting feature with Extent report, which is having many features along with it and can be considered as an intermediate level of reporting. 

You have to build a class to have the utilities to work with Extent report, and while doing so, you have to implement the interface ITestlistener from TestNg; the below code shows how : 

package com.cyborg.core.generic.reportUtils;

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.cyborg.core.generic.dataUtils.PropertiesDataUtils;

import io.appium.java_client.android.AndroidDriver;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.Augmenter;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.Reporter;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

public class ExtentReportUtils implements ITestListener {

  String screenShotPath = "";

  static ExtentReports extentReports;
  ExtentHtmlReporter extentHtmlReporter;
  protected ExtentTest extentTest;


  static String pathOfFile = "./configurator.properties";
  PropertiesDataUtils propertiesDataUtils = PropertiesDataUtils.getInstance(pathOfFile);
   Boolean log_to_kibana=Boolean.parseBoolean(PropertiesDataUtils.configDataStore.get("log_to_kibana"));
 
   public void setup() {
     try {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        Date now = new Date();
        String currentTime = simpleDateFormat.format(now);
        extentHtmlReporter = new ExtentHtmlReporter(
              new File(System.getProperty("user.dir") + "_Reports_" + currentTime + ".html"));
        extentHtmlReporter.loadXMLConfig(
              new File(System.getProperty("user.dir") + "/src/test/resources/config/extent-config.xml"));
        extentReports = new ExtentReports();
        extentReports.setSystemInfo("Environment", PropertiesDataUtils.configDataStore.get("Environment"));
        extentReports.setSystemInfo("AppName", PropertiesDataUtils.configDataStore.get("AppName"));
        extentReports.setSystemInfo("ModeOfExecution", PropertiesDataUtils.configDataStore.get("modeOfExecution"));

        extentReports.attachReporter(extentHtmlReporter);
        System.out.println("DONE SETUP FOR extent Report");
     } catch (Exception ex) {
        ex.printStackTrace();
     }
  }

  public void setup(String reportName) {
     extentReports = getExtent(reportName);
  }

  public ExtentReports getExtent(String reportName) {
     if (extentReports != null)
        return extentReports; // avoid creating new instance of html file
     extentReports = new ExtentReports();

     extentReports.attachReporter(getHtmlReporter(reportName));
     return extentReports;
  }

  private ExtentHtmlReporter getHtmlReporter(String reportName) {

     extentHtmlReporter = new ExtentHtmlReporter("./reports/" + reportName + ".html");
     extentHtmlReporter.loadXMLConfig("./src/test/resources/config/extent-config.xml");

     // make the charts visible on report open
     extentHtmlReporter.config().setChartVisibilityOnOpen(true);
     extentHtmlReporter.config().setDocumentTitle(PropertiesDataUtils.configDataStore.get("AppName"));
     extentHtmlReporter.config().setReportName("Regression Cycle");

     // Append the existing report
     extentHtmlReporter.setAppendExisting(false);
     Locale.setDefault(Locale.ENGLISH);
     return extentHtmlReporter;
  }

  public void registerTestMethod(Method method) {
     String testName = method.getName();
     extentTest = extentReports.createTest(testName);

  }

  public void sequenceScreenShot(AndroidDriver driver, String application, String step) {
     try {
        extentTest.addScreenCaptureFromPath(screenshotStepWise(driver, application, step));
     } catch (Exception e) {
        e.printStackTrace();
     }
  }

  public void screenshotAnyCase(ITestResult result, WebDriver driver, String application) {

     String testName = result.getName();
     File file = new File(".");
     String filename = testName + ".png";
     String filepath = null;
     try {
        filepath = file.getCanonicalPath() + "/ScreenShots/" + application + "/" + putLogDate() + filename;
     } catch (IOException e1) {
        e1.printStackTrace();
     }

     if (PropertiesDataUtils.configDataStore.get("run_on_jenkins").equalsIgnoreCase("true"))
        screenShotPath = "job/Cyborg2/" + PropertiesDataUtils.configDataStore.get("build_number")
              + "/artifact/ScreenShots/" + application + "/" + putLogDate() + filename;
     else
        screenShotPath = System.getProperty("user.dir") + "/ScreenShots/" + application + "/" + putLogDate()
              + filename;
     try {
        WebDriver augmentedDriver = new Augmenter().augment(driver);
        File screenshotFile = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(screenshotFile, new File(filepath));
        File reportFile = new File(filepath);
        reportLogScreenshot(reportFile, filename, application);
     } catch (Exception e) {
        Reporter.log("Unable to get the screenshot");
     }
  }

  public String screenshotStepWise(WebDriver driver, String application, String step) throws Exception {

     File file = new File(".");
     String filename = step + ".png";
     String filepath = null;
     try {
        filepath = file.getCanonicalPath() + "/ScreenShots/" + application + "/" + putLogDateWithoutmm() + filename;
     } catch (IOException e1) {
        e1.printStackTrace();
     }

     if (PropertiesDataUtils.configDataStore.get("run_on_jenkins").equalsIgnoreCase("true"))
        screenShotPath = "job/Cyborg2/" + PropertiesDataUtils.configDataStore.get("build_number")
              + "/artifact/ScreenShots/" + application + "/" + putLogDateWithoutmm() + filename;
     else
        screenShotPath = System.getProperty("user.dir") + "/ScreenShots/" + application + "/"
              + putLogDateWithoutmm() + filename;
     try {
        WebDriver augmentedDriver = new Augmenter().augment(driver);
        File screenshotFile = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(screenshotFile, new File(filepath));
     } catch (Exception e) {
        Reporter.log("Unable to get the screenshot");
     }
     return screenShotPath;
  }

  protected void reportLogScreenshot(File file, String fileName, String application) {
     System.setProperty("org.uncommons.reportng.escape-output", "false");
     String absolute = file.getAbsolutePath();
     if (PropertiesDataUtils.configDataStore.get("run_on_jenkins").equalsIgnoreCase("true"))
        absolute = " /job/Cyborg2/" + PropertiesDataUtils.configDataStore.get("build_number")
              + "/artifact/ScreenShots/" + application + "/" + putLogDate() + fileName;
     else
        absolute = System.getProperty("user.dir") + "/ScreenShots/" + application + "/" + putLogDate() + fileName;
     screenShotPath = absolute;

  }

  public void captureStatus(ITestResult result) {
     if (result.getStatus() == ITestResult.SUCCESS) {
        extentTest.log(Status.PASS, "The test method Named as :" + result.getName() + " is PASSED");
        try {
           extentTest.addScreenCaptureFromPath(screenShotPath);
        } catch (IOException e) {

           e.printStackTrace();
        }
     } else if (result.getStatus() == ITestResult.FAILURE) {
        extentTest.log(Status.FAIL, "The test method Named as :" + result.getName() + " is FAILED");
        extentTest.log(Status.FAIL, "The failure : " + result.getThrowable());
        extentTest.log(Status.FAIL, "StackTrace: " + result.getThrowable());
        try {
           extentTest.addScreenCaptureFromPath(screenShotPath);
        } catch (IOException e) {

           e.printStackTrace();
        }
     } else if (result.getStatus() == ITestResult.SKIP) {
        extentTest.log(Status.SKIP, "The test method Named as :" + result.getName() + " is SKIPPED");

     }

  }

  public String putLogDate() {
     Calendar c = new GregorianCalendar();
     c.add(Calendar.DATE, +0);
     Date s = c.getTime();
     String dateString = new SimpleDateFormat("_EEE_ddMMMyyyy_hhmm").format(s);
     return dateString;
  }

  public String putLogDateWithoutmm() {
     Calendar c = new GregorianCalendar();
     c.add(Calendar.DATE, +0);
     Date s = c.getTime();
     String dateString = new SimpleDateFormat("_EEE_ddMMMyyyy_hh").format(s);
     return dateString;
  }

  public void cleanup() {
     extentReports.flush();
  }

  public void onTestStart(ITestResult result) {

     /*
      * try { DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH-mm-ss"); Date
      * date = new Date();
      */
     /*
      * record = new ATUTestRecorder(System.getProperty("user.dir")+"/videos",
      * dateFormat.format(date), false); record.start();
      *//*
         *
         * } catch (ATUTestRecorderException e) { e.printStackTrace(); }
         */

  }

  public void onTestSuccess(ITestResult result) {

     /*
      * try { record.stop(); } catch (Exception e) { e.printStackTrace(); }
      */

     String testDescription = result.getMethod().getDescription();
     String testCaseNumber = testDescription.split("_")[0];
     String testDesc = testDescription.split("_")[1];
     String status = "PASSED";
     String exceptionType = "NA";
     String detailedError = "NA";
    
     String data ="{\n" +
           "   \"testCaseNumber\" : \""+testCaseNumber+"\",\n" +
           "   \"status\" : \""+status+"\",\n" +
           "   \"testDescription\" : \""+testDesc+"\",\n" +
           "   \"exceptionType\" : \""+exceptionType+"\",\n" +
           "   \"detailedError\":\""+detailedError+"\"\n" +
           "   \n" +
           "}";

     

  }

  @Override
  public void onTestFailure(ITestResult result) {
    
     String testDescription = result.getMethod().getDescription();
     String testCaseNumber = testDescription.split("_")[0];
     String testDesc = testCaseNumber.split("_")[1];
     String status = "FAILED";
     String exceptionType = String.valueOf(result.getThrowable().getClass().getSimpleName());
     String detailedError = String.valueOf(result.getThrowable().getMessage());
    
     String data ="{\n" +
           "   \"testCaseNumber\" : \""+testCaseNumber+"\",\n" +
           "   \"status\" : \""+status+"\",\n" +
           "   \"testDescription\" : \""+testDesc+"\",\n" +
           "   \"exceptionType\" : \""+exceptionType+"\",\n" +
           "   \"detailedError\":\""+detailedError+"\"\n" +
           "   \n" +
           "}";

    
     // TODO Auto-generated method stub

  }

  @Override
  public void onTestSkipped(ITestResult result) {
     String testDescription = result.getMethod().getDescription();
     String testCaseNumber = testDescription.split("_")[0];
     String testDesc = testCaseNumber.split("_")[1];
     String status = "SKIPPED";
     String exceptionType = result.getThrowable().getClass().getSimpleName();
     String detailedError = result.getThrowable().getMessage();
    
     String data ="{\n" +
           "   \"testCaseNumber\" : \""+testCaseNumber+"\",\n" +
           "   \"status\" : \""+status+"\",\n" +
           "   \"testDescription\" : \""+testDesc+"\",\n" +
           "   \"exceptionType\" : \""+exceptionType+"\",\n" +
           "   \"detailedError\":\""+detailedError+"\"\n" +
           "   \n" +
           "}";

  }

  @Override
  public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
     // TODO Auto-generated method stub

  }

  @Override
  public void onStart(ITestContext context) {
     // TODO Auto-generated method stub

  }

  @Override
  public void onFinish(ITestContext context) {
     // TODO Auto-generated method stub

  }
}

Conclusion : With this we are concluding the Selenium Page Object Model framework development through which you can start building the Page Object model framework and can take it to the advanced level , in the upcoming series of the tutorial we will discuss more on the advanced features of Selenium framework . To go through the series of Selenium tutorial you can go through here .

About Debarghya

Myself Debarghya Roy, I am an Engineering ARCHITECT working with fortune 5 company and an open source contributor, having around 12 years of experience/expertise in various Technology stack.
I have worked with various technologies such as Java,C#,Python,Groovy, UI Automation(Selenium), Mobile Automation(Appium), API/Backend Automation,Performance Engineering(JMeter, Locust), Security Automation(MobSF,OwAsp,Kali Linux, Astra,ZAP etc), RPA,Process Engineering Automation,Mainframe Automation,Back End Development with SpringBoot,Kafka,Redis,RabitMQ,ELK stack, GrayLog, Jenkins and also having experience in Cloud Technologies, DevOps etc.
I live in Bangalore ,India with my wife and have passion towards Blogging , music , playing guitar and my Philosophy of life is Education for All which gave the birth of LambdaGeeks. Lets connect over linked-in - https://www.linkedin.com/in/debarghya-roy/

Leave a Comment

Your email address will not be published. Required fields are marked *