Page Object Model for selenium webdriver

Like QTP, TestComplete and few other automation tools selenium webdriver does not provide any centralized repository where we can put object locator of page element. In POM object pattern we can accomplish this type approach.

What is POM:
In automated web testing, a Page Object is a class or object that represents a web page in your application. A Page Object hides the technical details about how you interact with a web page behind a more readable and business-focused facade. Following are the few points in details:
Page Object Model is a design pattern to create Object Repository for web UI elements. Like it provide you to option to put all locators in corresponding page (java file ) like for home page you  create a homepage java file and put all element locators of home page in same class.
Under this model, you should create java file like above ( homePage.java ) home page and create functions related to this page  like clickHomeMenu, clickProduct() verfiyHomePage() etc.
So your page object class contains elements locator and corresponding function what you need to perform on that particular page.
Name of these function and object locator must be logically defined like elements name username , password, loginButoon and corresponding function should be like enterUserName(), enterPassword(), clickLoginButton()


Advantages of POM
The tests are much more readable as only function need to call from different-2 page class files into your test files.
Page elements and logic is centralized in one place, this will help much easier in maintenance.
Easy to understand any new develpoer.
Easy to maintain in case of any changes in application or elements .
Object repository and function or independent from test scripts so we can use them in multiple test files.

Implementation of page object model:
In this example I will show you some example how to create POM model by using below url:
http://book.theautomatedtester.co.uk
When you open this url you will land at home page. Also when you click on “Chapter1”, “Chapter2” and “Chapter3” etc you will get other pages.
In page object model you should create java file for corresponding pages like I have created “HomePage.java”, “ChapterFirstPage.java”, “ChapterSecondPage.java” for home page, chapter 1 page chapter 2 page respectively. And put corresponding elements locator and functions.

1. HomePage.java

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class HomePage {

   private WebDriver driver;
  
   @FindBy(linkText="Chapter1")
   WebElement chapter1;
  
   @FindBy(linkText="Chapter2")
   WebElement chapter2;
  
   @FindBy(linkText="Chapter3")
   WebElement chapter3;
  

   public HomePage(WebDriver driver) {
          this.driver = driver;
   }
  
   public ChapterFirstPage clickChapterFirst(){
          chapter1.click();
          return PageFactory.initElements(driver, ChapterFirstPage.class);
   }
  
   public ChapterSecond clickChapterSecond(){
          chapter2.click();
         return PageFactory.initElements(driver, ChapterSecond.class);
   }
  
   public void clickChapterThird(){
         chapter3.click();              
   }
  }

2. ChapterFirstPage.java
package com.test.page;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.Select;

public class ChapterFirstPage {

   private WebDriver driver;

   @FindBy(id = "secondajaxbutton")
   WebElement secondajax;

   @FindBy(xpath = "//select[@id='selecttype']")
   WebElement dropdown;

   @FindBy(id = "verifybutton")
   WebElement verifybutton;

   public ChapterFirstPage(WebDriver driver) {
         this.driver = driver;
   }

   public ChapterFirstPage clickSecondAjaxButton() {
         secondajax.click();
         return PageFactory.initElements(driver, ChapterFirstPage.class);
   }

   public ChapterFirstPage clickSecondAjaxButton1(String data1) {
         System.out.println(data1);
         return PageFactory.initElements(driver, ChapterFirstPage.class);
   }

   public ChapterFirstPage selctDropDown() {
         new Select(dropdown).selectByVisibleText("Selenium Core");
         return PageFactory.initElements(driver, ChapterFirstPage.class);
   }

   public ChapterFirstPage verifyButton() {
         verifybutton.click();
         return PageFactory.initElements(driver, ChapterFirstPage.class);
   }

}

3. ChapterSecondPage.java

package com.test.page;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class ChapterSecondPage {

   private WebDriver driver;

   @FindBy(id = "//input[@name='but2']")
   WebElement but2;

   @FindBy(xpath = "//input[@id='random']")
   WebElement random;

   @FindBy(id = "Index")
   WebElement index;

   public ChapterSecondPage(WebDriver driver) {
         this.driver = driver;
   }

   public ChapterSecondPage clickRandom() {
         random.click();
         return PageFactory.initElements(driver, ChapterSecondPage.class);
   }

   public ChapterSecondPage clickbut2() {
         but2.click();
         return PageFactory.initElements(driver, ChapterSecondPage.class);
   }

   public HomePage clickIndex() {
         index.click();
         return PageFactory.initElements(driver, HomePage.class);
   }
  
   public String getTest() {
         return index.getText();                 
   }
}


So in above examples you can see that page elements locator are defined using @FindBy annotation and corresponding functions are defined which will separate from each others.
PageFactory class used to create run time object of page classes like:
PageFactory.initElements(driver, HomePage.class);

You should return object of class where you application move after performing actions like when I click index in ChapterSecondPage.java file it returm HomePage object as after clicking on index page Home page will open.
PageFactory.initElements(driver, HomePage.class);

Similar way another example when you click on clickbut2() then same page open
PageFactory.initElements(driver, ChapterSecondPage.class);

Now creating test file, you should create base class of all test scripts where you should put common functions related test case like I created “TestBase.java”

package com.test.util;

import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import com.test.page.ChapterFirstPage;
import com.test.page.ChapterSecondPage;
import com.test.page.HomePage;

public class TestBase {

   protected WebDriver driver;
   protected String baseUrl;
   protected HomePage homePage;
   protected ChapterSecondPage chapterSecond;
   protected ChapterFirstPage chapterFirstPage;

   @BeforeSuite
   public void setUp() {
         baseUrl = "http://book.theautomatedtester.co.uk/";
         driver = new FirefoxDriver();
         driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

   }
  

   @AfterSuite
   public void tearDown() throws Exception {
         driver.quit();

   }
}

To create test scripts and import TestBase class and call corresponding functions from page java file as needed in your test script.

package com.test.scripts;

import org.openqa.selenium.support.PageFactory;
import org.testng.annotations.Test;
import com.test.page.HomePage;
import com.test.util.TestBase;

public class MyTest extends TestBase {

   @Test
   public void testPageObject() throws Exception {

          homePage = PageFactory.initElements(driver, HomePage.class);

          driver.get(baseUrl);

          chapterSecond = homePage.clickChapterSecond();
          chapterSecond.clickbut2();
          chapterSecond.clickRandom();
          String data = chapterSecond.getTest();
          homePage = chapterSecond.clickIndex();

          chapterFirstPage = homePage.clickChapterFirst();
          chapterFirstPage.clickSecondAjaxButton();
          chapterFirstPage.clickSecondAjaxButton1(data);
          chapterFirstPage.selctDropDown();
          chapterFirstPage.verifyButton();

   }
}


Hope this will help you to design page object model in selenium webdriver. Leave comment in case you have any query.

3 comments:

  1. Hi! very usefull article
    I have idea how to improve thist test for more flexibuility
    for example we have common page objects which are on each page but with different names such as:
    1. PageWidget (same xpath in each page but with different name)
    2. PageTable(same xpath in each page)
    3. PageLink(same xpath in each page but with different name)

    and i want to use this common page objects to get some element on page like this:
    page().get(PageWidget .class, "Widget Name").get(PageTable.class, "Table Name").get(PageLink.class, "Link Name").click


    is it any way to configure this test?

    ReplyDelete
  2. Hi i wanted to know if @FindBy annotation implicitly invokes Implicit wait written in the code?

    Hi,,
    Could pls someone clarify these doubts:

    One webdriver script that i wrote is failing sometimes(not all the times i run).

    I feel the webdriver is passing the control to the next line of execution even before the browser loads the page completely. And since the element in that next line of code is not available that time,, the execution stops and the browser closes before executing next 7-8 steps.

    I am using Page Object Model (@FindBy) annotations.
    I wanted to know if @FindBy implicitly/internally invokes implicit wait?? Or do i need to include wait in some other place/way?

    This is how my code looks:

    @BeforeMethod
    public void preCondition()
    {
    String browserName=GetData.fromProperties(".\\data\\config.properties","browser");
    String url=GetData.fromProperties(".\\data\\config.properties","url");

    if(browserName.equals("FF"))
    {
    driver=new FirefoxDriver();
    }

    else if(browserName.equals("IE"))
    {
    System.setProperty("webdriver.ie.driver",".\\browser_exe\\IEDriverServer64bit.exe");
    driver=new InternetExplorerDriver();
    }

    driver.manage().window().maximize();
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    driver.get(url);

    }
    ------------------------------------------------------------------------------------------

    public class ImportDepartmentsPage {

    WebDriver driver;

    @FindBy(css = "a[id='btnDownloadTemplate']")
    private WebElement clickingHereLink;

    @FindBy(css = "a[id='btnImport']")
    private WebElement importButton;

    @FindBy(css = "input[id='Excel']")
    private WebElement browseButton;

    @FindBy(css = "a[id='btnClose']")
    private WebElement closeButton;

    @FindBy(css = "input[id='readOnly']")
    private WebElement browseTextbox;

    public ImportDepartmentsPage(WebDriver driver) {
    this.driver = driver;
    PageFactory.initElements(driver, this);
    }

    public void clickClickingHereLink() {
    clickingHereLink.click();
    }

    public void clickImportButton() {
    waitForFileToBeSelected(browseTextbox,"value", "AddDepartments.xlsx");
    importButton.click();
    }

    public void clickBrowseButton() {
    browseButton.click();
    }

    public void typeBrowseTextbox(String loc) {
    browseTextbox.sendKeys(loc);
    }

    public void clickCloseButton() {
    closeButton.click();
    }
    }

    ReplyDelete
  3. Hi,
    Can you please let me know how do we call two web element from other class in pom.
    Thanks in advance.

    ReplyDelete

Leave your comments, queries, suggestion I will try to provide solution