Page Object Model (POM) and Page Factory using Selenium WebDriver
What is the Page Object Model?
Page Object Model (POM) is a design principle, mostly used in test automation that creates Object Repository for web UI elements. It creates a separate Object Repository to store object locators. Under this model, for each web page, there should be a separate page class. The page class will have all object locators and most action methods preferably for the corresponding page. The main advantage of the model is that it will reduce the code duplication and improves test maintenance. Page Object Model (POM) can be used in any kind of framework like a data-driven, keyword-driven, modular, hybrid framework, etc.
Why POM?
Page Object Model has become the most popular test automation design pattern around the testing industry nowadays. POM facilitates as to concentrate the AUT rather than fixing the automation suite to perform the test. In-Page Object Model the information of the object is managed outside the test script, more than making it easy to understand the test script.
Advantages of the Page Object Model?
- Makes test code more readable
- Helps in quickly automating test cases
- Test cases are easy to maintain
- Testing new functionality becomes extremely easy.
- It makes test script maintenance very easy
- The code becomes less and optimized
- It avoids writing the duplicate locators for same WebElement which is the main issue that occurs in other frameworks
- We can develop our tests faster
- Can re-use earlier created objects for one test in another test
- You don’t need to change our test logic if UI changes, all we need to do is just we need amend the relevant Page Object(s) to reflect the changes- the test code remains the same.
- The Page Object Model approach makes test automation programmer more friendly, durable and comprehensive
- The main advantage in POM is our page Object Repository is Independent of Automation Tests. Keeping the separate repository for every page objects helps us to use this repository for different purposes with different frameworks like we integrate this repository with other tools like NUnit, JUnit, etc.
How to implement POM?
Simple POM:
It is a basic structure of Page Object Model (POM) where all the Web Elements of Application Under Test (AUT) and the Web Elements whose methods are operated are maintained inside a class file. A task like verification should be separate as a part of Test Methods.
Below are the steps to create a POM without Page Factory
1) We will create a Java Class for every web page in the application.
2) In each Java Class, declare all the Web Elements as variable.
3) Implement corresponding methods acting on the variables.
The design pattern can be implemented using 2 layers:
- Page Layer will have the pages of the application as individual Java Class. Each Class will have WebElements declared as variables and the actions that are performed as methods.
- Test Layer will hold the application test cases and its verification part.
Let’s take an example of a simple scenario:
- Open the URL of an application.
- Type the Email Address and password data.
- Click on the Login button.
Page Layer
HomePage: The page opens when the URL is entered and this is where we enter the data for login.
Steps To Create POM With Real-Time Examples
Step 1: Create a Java Class for two web Pages
In this example, we will access 2 web pages, “Home” and “Search” pages. Hence, we will create Java classes under Package Name com.automation.pages
Package Name: com.automation.pages
FaceBookHomePage.java
Step 2: Create WebElements as variables using ‘By’ Class:
- Email, Password, Login button field on the HomePage.
Step 3: Create methods for the actions performed on WebElements:
- Type action on the EmailAddress field.
- Type action on the Password field.
- Click action on the Login button.
FaceBookHomePage.java
package com.automation.pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class FaceBookHomePage { WebDriver driver; By EmailId = By.xpath("//div[contains(@name,'email')]"); By Password = By.xpath("//div[contains(@name,'pass')]"); By LoginButton = By.xpath("//div[contains(@id,'u_0_b')]"); public void typeEmail(String emailId) { driver.findElement(EmailId).sendKeys(emailId); } public void typePassword(String passwordtext) { driver.findElement(Password).sendKeys(passwordtext); } public void clickContinue() { driver.findElement(LoginButton).click(); } public FaceBookHomePage(WebDriver driverFromPreviousClass) { this.driver = driverFromPreviousClass; } }
Test Layer
Here we implement Test Cases in this class.
We create another package, com.automation.test, and create a Java Class here (MainClass.java).
Steps To Create Test Cases:
- Initialize the driver and provide the URL to open the application.
- Create an object of the PageLayer Class and pass the parameter as a driver instance.
- By using the object created we call the methods in the PageLayer Class to perform actions/verification.
- Close the driver.
package com.automation.test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import com.automation.pages.FaceBookHomePage; //import com.automation.pages.HomePage; public class MainClass { WebDriver driver; @BeforeTest public void SetDriver() { System.setProperty("webdriver.gecko.driver","F:\\drivers\\geckodriver.exe"); WebDriver driver = new FirefoxDriver(); driver.manage().window().maximize(); driver.get("https://www.facebook.com/"); } @Test public void verifyLogin() { FaceBookHomePage home = new FaceBookHomePage(driver); home.typeEmail("abcxyz@gmail.com");// Give your Mail Id home.typePassword("abtyhh@12345");// Give your Password home.clickContinue(); } @AfterTest public void CloseDriver() { driver.quit(); } }
What Is Pagefactory?
In Selenium the PageFactory Class is an extension to the Page Object design pattern. It is used to initialize the Page Object elements or instantiate the Page Objects itself. Annotations can also be created for elements as the describing properties may not always be descriptive to tell one object from the other. It is also used to initialize the elements of the Page class without having to use ‘FindElement’ or ‘FindElements’. To supply descriptive names of target objects to improve the code readability annotations can be used. To support the PageObject pattern, WebDriver’s support library which contains a factory class. The important feature of Page Factory is the Cache feature that will store all frequently used WebElement in the cache.
Let us know more clarity on the term PageFactory
- It provides an alternate way of creating an object repository in terms of syntax and semantics for the web elements on a page.
- It uses a different strategy to initialize the web elements.
- For UI web elements the object repository could be built by
- POM without PageFactory and
- POM with PageFactory
Let us consider a simple test scenario
Step 1: Create a TestBase class. In this, we create an object of WebDriver, maximize browser, implementing waits, launching URL, etc. In the below program, we have a taken chrome browser and set the System Property to launch a chrome browser.
TestBase.java (BASE CLASS)
- Create a Package tests
- Create a Class TestBase.Java
package tests; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; //import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public class TestBase { public static WebDriver driver = null; @BeforeSuite public void initialize() throws IOException{ System.setProperty("webdriver.gecko.driver","F:\\drivers\\geckodriver.exe"); driver = new FirefoxDriver(); //To maximize browser driver.manage().window().maximize(); //Implicit wait driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS); //To open facebook driver.get("https://www.facebook.com"); } @AfterSuite //Test cleanup public void TestClean() { TestBase.driver.quit(); } }
Step 2: Create classes for each page (Eg. Facebook Login Page, Facebook Inbox Page) to hold the element locators and their methods. Usually, we will create page objects for all available pages in the AUT. For each page, we create a separate class with a constructor and we will identify all the locators and keep them in one class so that we can reuse the locators in multiple methods. It is easy to do the maintenance, if there is any change in the UI, we can simply change on one Page.
Here, I create java files (FacebookLoginPage.java and FacebookInboxPage.java) for the corresponding pages (Facebook Login Page, and Facebook Inbox Page) to hold element locators and their methods.
FBHomePage.java (Webpage 1)
- Create a package pages
- Create a class FbHomePage
package pages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; public class FbHomePage { WebDriver driver; public FbHomePage(WebDriver driver){ this.driver=driver; } //Using FindBy for locating elements //@FindBy(how=How.XPATH, using="//div[text()='Settings']") WebElement profileDropdown; @FindBy(how=How.XPATH, using="//div") WebElement profileDropdown; @FindBy(how=How.XPATH, using="//text()[.='Log Out']/ancestor::span[1]") WebElement logoutLink; //@FindBy(how=How.XPATH, using="///div[text()='Good morning, Testing!']") WebElement loggedInUserNameText; // Defining all the Methods that can be performed in the Facebook home page // Method to click on Profile Dropdown public void clickOnProfileDropdown(){ profileDropdown.click(); } // Method to click on Logout link public void clickOnLogoutLink(){ logoutLink.click(); } // Method to verify LoggedIn Username Text //public String verifyLoggedInUserNameText(){ //String userName = loggedInUserNameText.getText(); //return userName; //} }
FBLoginPage.java (Webpage 2)
package pages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; public class FbLoginPage { WebDriver driver; public FbLoginPage(WebDriver driver){ this.driver=driver; } //Using FindBy for locating elements @FindBy(how=How.XPATH, using="//input[@type='email'][@name='email']") WebElement emailTextBox; @FindBy(how=How.XPATH, using="//input[@type='password'][@name='pass']") WebElement passwordTextBox; //@FindBy(how=How.XPATH, using="//input[@type='submit'][@id='u_0_5']") WebElement signinButton; @FindBy(how=How.ID, using = "u_0_b") WebElement signinButton; // Defining all the Methods that can be performed in the Facebook home page // Method to set Email in the email text box public void setEmail(String strEmail){ emailTextBox.sendKeys(strEmail); } // Method to set Password in the password text box public void setPassword(String strPassword){ passwordTextBox.sendKeys(strPassword); } // Method to click on Login Button public void clickOnLoginButton(){ signinButton.click(); } }
Step 3: Create Test (Eg., FBLoginTest) as per the above pages. As per my test scenario which has mentioned above the scripts run as.
- Launch browser and open facebook.com
- Enter user credentials and do sign in
- Verify the loggedIn user name and do logout
FBLoginTest.java (Test Case 1)
package tests; import org.openqa.selenium.support.PageFactory; import org.testng.annotations.Test; import pages.FbHomePage; import pages.FbLoginPage; public class FbLoginTest extends TestBase{ @Test public void init() throws Exception{ //driver.get("https://www.facebook.com"); FbLoginPage loginpage = PageFactory.initElements(driver, FbLoginPage.class); loginpage.setEmail("abcqwerty@gmail.com");//Set your Username loginpage.setPassword("xxxxyyyyzzzz");//Set your Password loginpage.clickOnLoginButton(); FbHomePage homepage = PageFactory.initElements(driver, FbHomePage.class); homepage.clickOnProfileDropdown(); homepage.verifyLoggedInUserNameText(); homepage.clickOnLogoutLink(); } }
Step 4: Create testng.xml file
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Everjobs Suite"> <test name="Page Object Model"> <classes> <class name="tests.TestBase" /> <class name="tests.FbLoginTest" /> </classes> </test> </suite> <!-- Suite -->
Now, if AUT undergoes any change at the login page or any other page we just need to change the page object where we don’t need to change our test script again and again. Now your project structure will look like as below.
Execute the testnG.xml file on the test suite and it will redirect to facebook.com webpage and enter all the credentials. It will then verify the username and then logout of the account. This is how we implement the Page Object Model with Page Factory.