Showing posts with label Page Object Model. Show all posts
Showing posts with label Page Object Model. Show all posts

Page Object Model (POM) using Page Factory in Selenium

In last post we have seen Page Object Model with basic approach, in this post we will see Page Object Model using Page Factory in Selenium.

What is PageFactory?
PageFactory Class in Selenium is an extension to the Page Object design pattern. It is used to initialize the web elements of the Page. It is used to initialize elements of a Page class without having to use 'FindElement' or 'FindElements'.

Here we follow the below steps to implement Page Object Model using Page Factory:

POM.xml
<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>POMPageFactory</groupId>
  <artifactId>POMPageFactory</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
  <dependency>
   <groupId>org.testng</groupId>
   <artifactId>testng</artifactId>
   <version>7.1.0</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-java</artifactId>
   <version>3.141.59</version>
  </dependency>
 </dependencies>
</project>

Steps to be followed to create Base Class
  • Declare web driver as static and Initialize the web driver and open the application using setup method.
  • Create an object of page layer class(Only need to create LoginPage object inside setup method).
  • Close the browser using tearDown method.
  • You can have some other common methods as well which will be used across framework like implicit waits, taking screen shots etc.
BaseClass.java
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import com.OrangeHRM.pages.LoginPage;

/**
 * @author Hitendra
 *  
 */
public class BaseClass {
 
 public static WebDriver driver;
 public LoginPage loginPage;
 
 @BeforeMethod
 public void setup() {
  System.setProperty("webdriver.chrome.driver",
    "C:\\Users\\Hitendra\\Downloads\\chromedriver_win32 (1)\\chromedriver.exe");
  driver= new ChromeDriver();
  driver.manage().window().maximize();
  driver.get("https://opensource-demo.orangehrmlive.com/index.php/auth/validateCredentials");
  loginPage=new LoginPage();
 }
 @AfterMethod
 public void tearDown() {
  driver.close();
 }
}

Steps to be followed to create page classes
  • Create a Java class for every page in the application (This class will extend BaseClass).
  • In each class, declare all the web Elements as variable using @FindBy.
  • Implement corresponding methods acting on the variables.
  • Construct page chaining logic - lets say in LoginPage.java we have login method and when we perform actions like entering username, password and clicking on login button then user lands HomePage. So login method will return object of HomePage.java class.
  • Add constructor to initialize the web elements initElements method.
Page Chaining Model
LoginPage.java
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

import com.OrangeHRM.base.BaseClass;

public class LoginPage extends BaseClass {
 
 @FindBy(id="txtUsername") 
 WebElement userName;
 
 @FindBy(name="txtPassword") 
 WebElement password;
 
 @FindBy(xpath="//*[@id=\"btnLogin\"]") 
 WebElement loginBtn;
 
 @FindBy(xpath="//*[@id=\"divLogo\"]/img") 
 WebElement logo;
 
 public LoginPage() {
  PageFactory.initElements(driver, this);
 }
 
 public boolean validateLogo() {
  logo.isDisplayed();
  return true;
 }
 //This method will return object of HomePage class as we are landing on 
 //HomePage using this method
 public HomePage login(String uname, String pswd) {
  userName.sendKeys(uname);
  password.sendKeys(pswd);
  loginBtn.click();
  return new HomePage();
 }
}

HomePage.java
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import com.OrangeHRM.base.BaseClass;

public class HomePage extends BaseClass {
 
 @FindBy(xpath="//*[@id=\"menu_admin_viewAdminModule\"]/b")
 WebElement adminTab;
 
 public HomePage() {
  PageFactory.initElements(driver, this);
 }
 //This method will return object of SystemUsersPage class as we are landing on 
 //SystemUsersPage using this method
 public SystemUsersPage clickOnAdminTab() {
  adminTab.click();
  return new SystemUsersPage();
 }
}

SystemUsersPage.java -  Just created this page class without writing anything inside it.
public class SystemUsersPage {

}

Steps to be followed to create test cases
  • Create test class for every corresponding page class. Like LoginPageTest, HomePageTest etc. (This class will extend BaseClass).
  • Using the object reference, call the method from page layer class.
  • Insert the assert in the test method to validate the scenarios.
  • Repeat step#3 until all actions are performed.
LoginPageTest.java
import org.testng.Assert;
import org.testng.annotations.Test;
import com.OrangeHRM.base.BaseClass;
import com.OrangeHRM.pages.HomePage;

public class LoginPageTest extends BaseClass {
 HomePage homePage;
 
 @Test(priority = 1)
 public void logoTest() {
  boolean flag=loginPage.validateLogo();
  Assert.assertTrue(flag);
 }
 @Test(priority = 2)
 public void loginTest() {
  homePage=loginPage.login("admin", "admin123");
  String expectedURL="https://opensource-demo.orangehrmlive.com/index.php/dashboard";
  String actualURL=BaseClass.driver.getCurrentUrl();
  Assert.assertEquals(actualURL, expectedURL);
 }
}

HomePageTest.java
import org.testng.Assert;
import org.testng.annotations.Test;
import com.OrangeHRM.base.BaseClass;
import com.OrangeHRM.pages.HomePage;

public class HomePageTest extends BaseClass {
 HomePage homePage;
 
 @Test(priority = 3)
 public void clickOnAdminTab() throws InterruptedException  {
  homePage=loginPage.login("admin", "admin123");
  homePage.clickOnAdminTab();
  Thread.sleep(2000);
  String expectedURL="https://opensource-demo.orangehrmlive.com/index.php/admin/viewSystemUsers";
  String actualURL=BaseClass.driver.getCurrentUrl();
  Assert.assertEquals(actualURL, expectedURL);
 }
}

testng.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite">
  <test thread-count="5" name="Test">
    <classes>
      <class name="com.OrangeHRM.testcases.LoginPageTest"/>
      <class name="com.OrangeHRM.testcases.HomePageTest"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->

YouTube video will be coming soon...

Introduction to Page Object Model(POM)

What is Page Object Model?
Page Object Model is a design pattern to create Object Repository for web UI elements. Under this model, for each web page in the application, there should be corresponding page class. This Page class will find the Web Elements of that web page and also contains Page methods which perform operations on those Web Elements.
Non POM structure Vs POM Structure

POM Advantages and Disadvantages:
Advantages:
  • Object Repository: You can create an Object Repository of the fields segmented page-wise. This as a result provides a Page Repository of the application as well. Each page will be defined as a java class. All the fields in the page will be defined in an interface as members. The class will then implement the interface.
  • Reusability:  We can reuse the page class if required in different test cases .
  • Functional Encapsulation: All possible functionality or operations that can be performed on a page can be defined and contained within the same class created for each page. This allows for clear definition and scope of each page's functionality.
  • Low maintenance: Any User Interface changes can swiftly be implemented into the interface as well as class.
  • Programmer Friendly: Robust and more readable. The Object-oriented approach makes the framework programmer friendly.
  • Low Redundancy: Helps reduce duplication of code. If the architecture is correctly and sufficiently defined, the POM gets more done in less code.
  • Efficient & Scalable: Faster than other keyword-driven/data-driven approaches where Excel sheets are to be read/written.
Disadvantages:
  • High Setup Time & Effort:  Initial effort investment in development of Automation Framework is high. This is the biggest weight of POM in case of web applications with hundreds/thousands of pages. It is highly suggested that if this model is decided to be implemented, then it should be done parallel to development of the application.
  • Skilled labour: Testers not technically sound or aware of programming best practices are a nightmare in this case. 
There are two ways to implement Page Object Model.
Basic Approach 
Page Factory approach (@FindBy Annotation)

Steps to be followed to create page classes
  • Create a Java class for every page in the application.
  • In each class, declare all the web Elements as variable.
  • Implement corresponding methods acting on the variables.
Steps to be followed to create test cases
  • Initialize the driver and open the application.
  • Create an object of page layer class and pass the driver instance.
  • Using the object call the method from page layer class
  • Repeat step#3 until all actions are performed and at the end close the browser.
Below implementation given using basic approach:

LoginPage Class:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage {
 WebDriver driver;
    //UI Elements
 By username = By.id("txtUsername");
 By password = By.name("txtPassword");
 By loginBtn = By.xpath("//*[@id=\"btnLogin\"]");
 By logo = By.xpath("//*[@id=\"divLogo\"]/img");
    
 //Constructor to initialize current class objects 
 public LoginPage(WebDriver driver) {
  this.driver=driver;
 }
 //User Actions methods
 public boolean validateLogo() {
  driver.findElement(logo).isDisplayed();
  return true;
 }
 public HomePage login(String uname, String pswd) {
  driver.findElement(username).sendKeys(uname);
  driver.findElement(password).sendKeys(pswd);
  driver.findElement(loginBtn).click();
  return new HomePage();
 }
}

LoginPageTest Class:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.orangeHRM.pages.HomePage;
import com.orangeHRM.pages.LoginPage;

/**
 * @author Hitendra
 *  
 */
public class LoginPageTest {
 public WebDriver driver;
 LoginPage loginPage;
 HomePage homepage;
 
 @BeforeMethod
 public void setUp() {
  System.setProperty("webdriver.chrome.driver",
    "C:\\Users\\Hitendra\\Downloads\\chromedriver_win32 (1)\\chromedriver.exe");
  
  driver= new ChromeDriver();
  loginPage= new LoginPage(driver);
  driver.manage().window().maximize();
  driver.get("https://opensource-demo.orangehrmlive.com/index.php/auth/validateCredentials");
 }
 @Test
 public void varifyLogo() {
  
  boolean flag=loginPage.validateLogo();
  Assert.assertTrue(flag);
 }
 @Test
 public void varifyLogin() {
  homepage=loginPage.login("admin", "admin123");
  String actualURL= driver.getCurrentUrl();
  String expectedURL= "https://opensource-demo.orangehrmlive.com/index.php/dashboard";
  Assert.assertEquals(actualURL, expectedURL);
 }
 @AfterMethod
 public void tearDown() {
  driver.close();
 }
}

Please refer below YouTube video: