Page Object Model is an object design pattern implementation of Page factory in Selenium, where web pages are represented as java classes, and the various elements on the page are defined as a method on the PO classes. All reusable methods are stored in libraries.
In this tutorial, we are going to create a simple framework for a google page with Selenium Webdriver.
Reading QR Code from the website using Webdriver
Page Object class contains all the page object(web elements) for a particular page. For every page present in the application, we have to write the Page Object class.
Page Object class name should end with PO so that it will be easy for the user to identify the class.
Steps to Create :
Different ways to create Page Object (Web element in PO class):
1. @FindBy :
@FindBy helps selenium testers to find the element on the webpage; to declare elements in PO class, we can use @FindBy with the following syntax.
@FindBy(locator = "locator value")
public WebElement elementName;
// method 1 using FindBy
@FindBy(name="q")
public WebElement searchBar;
public GooglePO(WebDriver driver) {
PageFactory.initElements(driver, this);
}
The disadvantage with this way is, we cannot use varying values at the place of locator value; it always should be a constant String.
Xpath in Selenium
We can create methods for the web elements using java static methods, which return web elements; static method way provides us the flexibility to handle varying locators; this method accepts driver as a parameter.
public static WebElement methodName(WebDriver driver){
return driver.findElement(By.locator(locator value));
}
// method 2 using static method
public static WebElement searchButton(WebDriver driver){
return driver.findElement(By.xpath("//input[contains(@value,'Search')]"));
}
The disadvantage of this way is when the user runs the test cases in parallel, there is a chance to fail because we are using static methods. Only one copy of static methods exists per class.
To help multi-threading/ parallel execution, we have to use non-static methods to create page objects, We have to write a constructor in these classes, and the constructor should accept the driver as a parameter. Using this driver, we have to assign a global driver present in the PO class
// method 2 using non static method
public WebElement methodName(){
return driver.findElement(By.locator(locator value));
}
// method 2 using non static method
public WebElement logoOnSearchResult(){
return driver.findElement(By.xpath("//h1/a[@id='logo']"));
}
The complete PO class looks like the below program.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class GooglePO {
private WebDriver driver;
// method 1 using FindBy
@FindBy(name="q")
public WebElement searchBar;
public GooglePO(WebDriver driver) {
// this is for non static method way
this.driver = driver;
PageFactory.initElements(driver, this);
}
// method 2 using static method
public static WebElement searchButton(WebDriver driver){
return driver.findElement(By.xpath("//input[contains(@value,'Search')]"));
}
// method 2 using non static method
public WebElement logoOnSearchResult(){
return driver.findElement(By.xpath("//h1/a[@id='logo']"));
}
}
1. Create packed called test
2. Create a Java Class called GoogleSeachTest
3. Open Firefox browser by setting the geckodriver.exe path to the system variable
// set gecko driver.exe file path
System.setProperty("webdriver.gecko.driver", "C:/~/geckodriver.exe");
// create object for browser
WebDriver driver = new FirefoxDriver();
4. Navigate to google.com
driver.get("https://google.com");
5. Create an object for GooglePO class, in which we have stored our page object (web elements), pass driver as a parameter
GooglePO gp = new GooglePO(driver);
6. (method 1) With the help of GooglePO class object access the element created by the @FindBy
gp.searchBar.sendKeys("POM test");
7. (method 2) We can access static members using the Class name, access the searchButton using GooglePO class name.
GooglePO.searchButton(driver).click();
8. (method 3) Acces non-static method using GooglePO class object
gp.logoOnSearchResult().click();
The complete program of the Test class looks like below.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import po.GooglePO;
public class GoogleSeachTest {
public static void main(String[] args) {
// set gecko driver.exe file path
System.setProperty("webdriver.gecko.driver", "C:/~/geckodriver.exe");
// create object for browser
WebDriver driver = new FirefoxDriver();
// navigate to google
driver.get("https://google.com");
// create object for GooglePO class
GooglePO gp = new GooglePO(driver);
// access searchBar page object from GooglPO PO class
gp.searchBar.sendKeys("POM test");
// accessing static method
GooglePO.searchButton(driver).click();
// access non static method using object of GooglePO class
gp.logoOnSearchResult().click();
}
}
We can also use a variable for writing the page object (web element) in selenium, but the only issue is you cannot customize much in the case of variables.
Below example only to showcase that we can also use a variable for page object but do not use it in the framework.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class POWithVariable {
WebDriver driver;
public POWithVariable(WebDriver driver) {
this.driver = driver;
}
// variable as page objects
public WebElement searchBar = driver.findElement(By.name("q"));
public WebElement searchButton = driver.findElement(By.xpath("//input[contains(@value,'Search')]"));
public WebElement logo = driver.findElement(By.xpath("//h1/a[@id='logo']"));
}
We have used this.driver = driver; code a couple of times on this page, but what does that mean.
this keyword points to the object of the class created by the constructor, as this global driver Webdriver driver; is not initialized.
We want to initialize the 'global level driver' value with the help of the user, so we accept driver value in the constructor with a parameter of driver, and we set 'constructor level driver' value to the 'global level driver', so that we can use the 'global level driver' in all the methods or where ever required.
In the next tutorial, we will learn the fully-featured Page Object Model Framework
Hybrid Inheritance in Java and Selenium
I am Pavankumar, Having 8.5 years of experience currently working in Video/Live Analytics project.