Page Object Model

Page Object Model(POM) is an object design pattern implementations of Page factory in protractor, where web pages are represented as Typescript classes, and the various elements on the page are defined as method on the PO classes. All reusable methods are stored in libraries

  • Page Object Model(POM) is one of the implementations of design pattern called Page Factory.
  • In protractor, we will create Page Object Modal class to develop and store the re-usable methods. These methods are nothing but Page Objects
  • Page Objects are nothing but web elements present in the web page like Buttons, links, tabs, textbars
  • We have to create page object class for every page present in the application, if the application is single page application (spa) we have to create page object classes for each tabs

Folder structure of the POM framework in protractor: page-object-model-folder-structure-protractor-pom

Value selected or not in dropdown

Page Objects Class in TypeScript

Page Object class contains all the page object(web elements) for a particular page. For every page present application, we have to write the Page Object class.

Page Object class name should end with PO, so that it will be easy for user to identify page object class.

Below code is example for the Page objects in typescript, we will discuss how to form page object in javascript in next topic

  • Create new folder and name it as PageObjectModel_CherCherTech
  • Create another folder called PO.
  • Create new file inside the PO folder and name it as GooglePO.ts, saving with ts extension is very important
  • Create class called GooglePO and export it

  • Page Object through Variables :

  • Create a variable called searchbar inside the GooglePO class.
  • Find the search bar and assign that ElementFinder to the searchbar variable.

  • 
        public static googleSearch = element(by.name("btnK"))			
    


    Page Objects through Methods :

  • Create public method called feelingLucky() inside the GooglePO class
  • Find the feeling lucky button and return it
  • 
        // using method
        feelingLucky(){
            return element(by.name("btnI"))
        }			
    


Complete code for the Page Objects in protractor


import { browser, element, by } from "protractor";
export class GooglePO{
    // using variables
    public static searchBar = element(by.name("q"))
    public static googleSearch = element(by.name("btnK"))
    // using method
    feelingLucky(){
        return element(by.name("btnI"))
    }
}			


Handle Hidden division Pop Up / Calender Pop up using Protractor

Library files in Page object model in Protractor

Sometimes we may have a repeating test steps across script, in such cases we have to create those steps as re-usable methods. Re-usable methods can be used across multiple scripts in framework

  • Create a folder called Lib inside the PageObjectModel_CherCherTech
  • Create a file called GoogleLib, the name should match with your PO file except the suffix
  • Create a class called GoogleLib, the name should match with your PO file except the suffix
  • Write a public method searchGoogle(), which accepts a string parameter
  • Inside searchGoogle() place google searching code
  • 
    searchGoogle(searchTerm :string){
    	GooglePO.searchBar.sendKeys(searchTerm)
    	GooglePO.searchButton.click()
    }			
    


Complete code for Library files


import { GooglePO } from "../PO/GooglePO";
export class GoogleLib{
    searchGoogle(searchTerm :string){
        GooglePO.searchBar.sendKeys(searchTerm)
        GooglePO.searchButton.click()
    } 
}		


Handle Authentication Pop Up in Protractor

Spec files

Spec files will have our test codes, it is important to have separate folder for every category.

  • Create a folder called Specs in inside the PageObjectModel_CherCherTech folder
  • Create a file called GoogleSpec.ts, this should match with PO and Lib file names except the suffix
  • Create describe and It blocks for test cases

import { browser } from "protractor";
import { GoogleLib } from "../Lib/GoogleLib";
import { GooglePO } from "../PO/GooglePO";
let googleLib = new GoogleLib()
describe("Page Object Model in Protractor",function(){
  browser.ignoreSynchronization = true; // for non-angular websites
  it("Search Google",function(){
    browser.get("https://google.com")
    googleLib.searchGoogle("chercher tech")
  });
  it("click operation",function(){
    browser.get("https://google.com")
    GooglePO.feelingLucky().click()
  });
});			


Conf file for the test


exports.config = {
  // launch locally when fields directConnect and seleniumAddress are not provided
  chromeDriver: 'D:/Eclipse progs/driverserver/chromedriver.exe',
  seleniumServerJar: 'D:/Eclipse progs/jars/selenium-server-standalone-3.11.0.jar',
  specs: ['D:\\Protractor Demo\\JSFilesLocation\\PageObjectModel_CherCherTech\\specs\\test.js'],
  capabilities: {
	browserName: 'chrome'
  }
}			


By this time, You might got idea how the Page object model will work. If you are only looking for this then your search ends now.

But if you are looking for enhancements in page object model the please do follow the following topics as well.

keep the above structure, I will mention what are the changes to make in existing file or new file if required

Protractor Interview Questions

Video Tutorial for POM in Protractor :

Subscribe to my youtube channel :


JSON File Data for Page Object Model(POM)

While creating POM framework it is important to read data from the external files, so in below code we would be reading values from Json File.

In this JSON class we have to write methods to read and write the data from the JSON file.

  • Create a folder called 'utility' inside the PageObjectModel_CherCherTech folder.
  • Create a file called jsonUtility.ts
  • Create Class inside the 'jsonUtility.ts' called JSONutils
  • In this class we have to write function for reading and writing the JSON files
  • Please do visit JSON reading and writing in Protractor tutorial.

JSON data file named as 'cherchertech.json'


{
	"name": "karthiq",
	"age": 27,
	"gender": "Male",
	"website": "cherchertech protractor"
}			


JSON file Reading Code.


// import the fs module
const fs = require('fs');
export class JSONutility{
    public readData(path:string, propertyToRetrieve:string){
        // read the file into raw data
        let rawdata = fs.readFileSync(path);
        // parse the raw data into meaningful JSON format
        let author = JSON.parse(rawdata);
        let websiteValue = author["website"]
        return websiteValue
    }
}		


Now read the 'website' property from JSON file as our search term. Please make changes in existing it block or add this as new it block in test spec file

We have to pass the path of the JSON file and the 'property' to read from the JSOn file to make the JSON reading for common to all.


it("Search Google with JSON reading",function(){
    browser.get("https://google.com")
    let searchTerm = jsonutil.readData("./cherchertech.json", "website")
    googleLib.searchGoogle(searchTerm)
  });		


read-json-file-pom-protractor

Scroll an element Into View using JavaScript Executor in Protractor

Read Excel data for POM

Data could be stored in Excel sheets as well in Page Object Model(POM), in such cases we have to create a utility class to read the data from the excel sheet file in POM.

  • Create a file called excelUtility.ts
  • Create Class inside the 'excelUtility.ts' called EXCELutils
  • In this class, we have to write function for reading and writing the EXCEL files
  • Please do visit EXCEL reading and writing in Protractor tutorial.
  • We can read the excel sheet using ExcelJS modules in protractor with Javascript/Typescript
  • Find the numbering for rows and cells
  • excel-file-pom-protractor-api

Excel reading utility in typescript protractor


import {Workbook, Row, Cell, Worksheet} from 'exceljs';
const wb:Workbook = new Workbook();
export class EXCELutility{
    
    public readExcel(excelPath:string, sheetName:string,
        rowNumber:number, columNumber:number){
            // read xlsx file type and return entire function after receiving return
            return wb.xlsx.readFile(excelPath).then(function(){
            //sheet object
            let sheet:Worksheet = wb.getWorksheet(sheetName);
            //row objct
            let rowObject:Row = sheet.getRow(rowNumber);
            // cell object
            let cellObject:Cell = rowObject.getCell(columNumber);
            // get value from cell
            let cellvalue = cellObject.value
            // return valu from function
            return cellvalue
        })
    }
}		


If you notice i have used two return statements in the above code, return cellvalue is to return the value to the function readFile, return wb.xlsx.readFile returns a promise contains the value that was received as return from cellvalue


import { browser } from "protractor";
import { GoogleLib } from "../Lib/GoogleLib";
import { EXCELutility } from "../utility/excelutility";
let googleLib = new GoogleLib()
let excelutil = new EXCELutility();
describe("Page Object Model in Protractor",function(){
  browser.ignoreSynchronization = true; // for non-angular websites
  it("Search Google",function(){
    browser.get("https://chercher.tech")
    excelutil.readExcel("test.xlsx", "Sheet1", 2, 1).then(function(searchTerm){
      console.log(searchTerm)
      googleLib.searchGoogle(searchTerm.toString())
    })
  });
});	


excel-value-pom-protractor-api

Package.json with Protractor

Winston Logging in Page Object Model in Protractor

It is crucial to do the logging in the frameworks execution, In protractor we will be using the winston logging page to track the logs.

  • Create folder called 'loggingutility' inside PageObjectModel_CherCherTech folder
  • Create a file called winstonutility.ts
  • Create class called Logger inside winstonutility.ts file
  • We should use the 'logger' static variable present in the Logger class to log he comment
  • I suggest to read full tutorial on Logging with winston in protractor typescript

import {createLogger, format, transports} from 'winston'
export class Logger{
    static logger = createLogger({
        level: 'info',
        format: format.simple(),
        transports: [
        // - Write to all logs with level `info` and above to `combined.log`
        new transports.File({ filename: 'combined.log'}),
				// - Write all logs error (and above) to Console/terminal
        new transports.Console()
        ]
    });
}


Above logger will write the logs to console and files as well.

Test File and there is no change to conf file


import { browser } from "protractor";
import { GoogleLib } from "../Lib/GoogleLib";
import { EXCELutility } from "../utility/excelutility";
import { Logger } from "../loggingutility/winstonutility";
let googleLib = new GoogleLib()
let excelutil = new EXCELutility();
let log = Logger.logger
describe("Page Object Model in Protractor",function(){
  browser.ignoreSynchronization = true; // for non-angular websites
  it("Search Google",function(){
    // logging using log methods
    log.log("warn", "warn message from test")
    browser.get("https://google.com")
    // logging using info() methods
    log.info("Opening Google webpage")
    excelutil.readExcel("test.xlsx", "Sheet1", 2, 1).then(function(searchTerm){
      // logging with log method
      log.log("info", "The value read from Excel is :"+searchTerm)
      console.log(searchTerm)
      googleLib.searchGoogle(searchTerm.toString())
    })
  });
});	


winston-logging-page-object-model-protractor

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions
  • Krishna
    Hi Karthik,
    
    Firstly, thank you the detailed tutorial. I'm trying to follow your approach and implement the same. 
    
    I'm having trouble directly calling the methods from the PO  folder as your calling on your sample code.
    
    Ex:
    
    I have a PO file abc.po.ts and it has a method 
    
    export class TcpPO{
    
        //page object using variable 
        public static PageHeader = element(by.xpath("//h1[contains(text(),'simple')]"));
    
    //page object using a method 
    create(){
     return element(by.id("test"));
        }
    
    When i try to call this method in my spec class 
    
    AbcPO. create().click();  // this line is throwing me an error {{ Property 'createNewTCP' does not exist on type 'typeof TcpPO'.ts(2339) }}
    
    Please help me with this 
    
    Thanks
    krishna
    Reply
  • Naveen
    Hi KarthiQ,
    
    Can you please add any videos or article for protractor with Cucumberjs - that would really help many people .
    
    Thanks,
    B.V.Naveen
    Reply
  • onotolei
    Hi. Have you already done this topic abot POM in JavaScript?
    Reply
    • karthiQ [ admin]
      Hi onotolei,
      I am intended to do, even i have few paragraphs written on this article but i have commented them as I need to write new article about the JS and POM. I will write it soon.
      Reply
  • Protractor Training

    new tutorial I am starting new Protractor training batch on Weekends. It is two days course from 01-june-2019 to 02-june-2019 based on class room (BANGALORE)

    Interested people can confirm the seat by calling to +91 8971673487 or whatsapp to +91 9003381224

    Find the course content : View Content