In Focus

Page Object Model Design Pattern 💻 In Selenium Web Driver

In this article, we will learn page object model design pattern in Selenium web driver.

Introduction
 
Page Object Model, also known as POM, is a design pattern in Selenium which has gained more popularity in the market for test automation development for the maintenance of code, such as reusability, extensibility, and avoiding code duplication etc.
 
Page Object Model is used for creating Control properties or Object Repository for controls on a webpage. For each webpage which we want to automate there should be a separate class such as if we are performing the automation for the login page, we need to maintain all the login page control properties in the separated class file. If we consider a login page, there are controls available in a login page such as UserName, Password, Login, ForgetPassword etc.
 
Each control will have unique control properties such as Name, Control ID, TagName, XPath, ClassName, CssSelector etc. To get the control properties we need to inspect the element by clicking F12 or right the webpage and clicking on Inspect Element.
 
There we can hover over the control to find a control property for each control. If the control doesn't have a control property then we need to use XPath. In order to take XPath right click on the control's element which is in the Inspect Element window, then click on Copy-->Copy XPath. 
 
If we want to automate a login page then we need to create a separate class as LoginObjectProperties and maintain all the login related control properties in LoginObjectProperties class.
 
Similarly, if we want to automate the registration page, we will have control under registration page like Enter Email, FirstName, LastName, City, ZipCode, Country etc. For registration page, we need to create a separate class called RegisterationObjectProperties and keep all the registration related control properties in RegisterationObjectProperties class.
 
The maintenance of a separate class for object properties or control properties is used for reducing the duplication of code as well as to reuse the code.
 
Example For Page Object Model, 
  1. using MbUnit.Framework;  
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;  
  3. using OpenQA.Selenium;  
  4. using OpenQA.Selenium.Chrome;  
  5. using OpenQA.Selenium.Support.UI;  
  6. using System;  
  7. using System.Collections.Generic;  
  8. using System.Linq;  
  9. using System.Text;  
  10. using System.Threading;  
  11. using System.Threading.Tasks;  
  12.   
  13. namespace PageObjectModel  
  14. {  
  15.     [TestClass]  
  16.     public static class ControlProperties  
  17.     {  
  18.   
  19.   
  20.         public static By signupClick = By.XPath("//*[@id='ctl00_HeaderHomeNewDesign_Login1_HyperLinkRegister']");  
  21.         public static By email = By.Name("ctl00$ContentMain$TextBoxEmail");  
  22.         public static By firstName = By.Name("ctl00$ContentMain$TextBoxFirstName");  
  23.         public static By lastName = By.Name("ctl00$ContentMain$TextBoxLastName");  
  24.         public static By password = By.XPath("//*[@id='ctl00_ContentMain_TextBoxPassword']");  
  25.         public static By confirmPassword = By.Name("ctl00$ContentMain$TextBoxPasswordConfirm");  
  26.         public static By countryDropdown = By.Name("ctl00$ContentMain$DropdownListCountry");  
  27.         public static By zipCode = By.Name("ctl00$ContentMain$TextBoxZip");  
  28.         public static By city = By.Name("ctl00$ContentMain$TextBoxCity");  
  29.         public static By securityQuestion = By.Name("ctl00$ContentMain$DropdownListSecurityQuesion");  
  30.         public static By securityAnswer = By.Id("ctl00_ContentMain_TextBoxAnswer");  
  31.         public static By sendMeUpdates = By.Id("ctl00_ContentMain_CheckBoxNewsletter");  
  32.         public static By iAccept = By.Name("ctl00$ContentMain$cbxIsGDPRAccepted");  
  33.         public static By registerMe = By.XPath("//*[@id='ctl00_ContentMain_ButtonSave']");  
  34.         public static By homeClick = By.XPath("//*[@id='ctl00_HeaderNewDesign1_HeaderMenu']/div/div/ul/li[1]/a");  
  35.         public static By searchClick = By.Name("ctl00$HeaderHomeNewDesign$searchImageButton");  
  36.         public static By authorSearchClick = By.Id("tabAuthorSearch");  
  37.         public static By authorFirstName = By.Id("TextBoxFirstName");  
  38.         public static By searchBtn = By.XPath("//*[@id='ctl00_ContentMain_PanelAuthorSearch']/input[3]");  
  39.         public static By profileClick = By.XPath("//*[@id='authorSearchResult']/div/div/ul/li[1]/a/span");  
  40.         public static By articlesClick = By.XPath("//*[@id='divContributes']/ul/li[1]/a");  
  41.         public static By firstArticleClick = By.XPath("//*[@id='ctl00_ContentMain_contentBoxUL']/li[1]/div[2]/h3/a");  
  42.     }  
  43.   
  44.     public class PageObjectModelMethods  
  45.     {  
  46.         IWebDriver webDriver;  
  47.         public PageObjectModelMethods(IWebDriver driver)  
  48.         {  
  49.             this.webDriver = driver;  
  50.         }  
  51.   
  52.         public void SignUpClick()  
  53.         {  
  54.             webDriver.FindElement(ControlProperties.signupClick).Click();  
  55.             WaitTime();  
  56.         }  
  57.   
  58.         public void EnterEmail(string userEmail)  
  59.         {  
  60.             webDriver.FindElement(ControlProperties.email).Clear();  
  61.             webDriver.FindElement(ControlProperties.email).SendKeys(userEmail);  
  62.             WaitTime();  
  63.         }  
  64.   
  65.         public void FirstName(string userFirstName)  
  66.         {  
  67.             webDriver.FindElement(ControlProperties.firstName).Clear();  
  68.             webDriver.FindElement(ControlProperties.firstName).SendKeys(userFirstName);  
  69.             WaitTime();  
  70.         }  
  71.   
  72.         public void LastName(string userLastName)  
  73.         {  
  74.             webDriver.FindElement(ControlProperties.lastName).Clear();  
  75.             webDriver.FindElement(ControlProperties.lastName).SendKeys(userLastName);  
  76.             WaitTime();  
  77.         }  
  78.   
  79.         public void Password(string userPassword)  
  80.         {  
  81.             webDriver.FindElement(ControlProperties.password).Clear();  
  82.             webDriver.FindElement(ControlProperties.password).SendKeys(userPassword);  
  83.             WaitTime();  
  84.         }  
  85.   
  86.         public void ConfirmPassword(string userConfirmPassword)  
  87.         {  
  88.             webDriver.FindElement(ControlProperties.confirmPassword).Clear();  
  89.             webDriver.FindElement(ControlProperties.confirmPassword).SendKeys(userConfirmPassword);  
  90.             WaitTime();  
  91.         }  
  92.   
  93.         public void CountryDopDown(string countryName)  
  94.         {  
  95.             IWebElement countryDrop = webDriver.FindElement(ControlProperties.countryDropdown);  
  96.             countryDrop.Click();  
  97.             SelectElement select = new SelectElement(countryDrop);  
  98.             select.SelectByValue(countryName);  
  99.             WaitTime();  
  100.         }  
  101.   
  102.         public void ZipCode(string userZipCode)  
  103.         {  
  104.             webDriver.FindElement(ControlProperties.zipCode).Clear();  
  105.             webDriver.FindElement(ControlProperties.zipCode).SendKeys(userZipCode);  
  106.             WaitTime();  
  107.         }  
  108.   
  109.         public void City(string userCity)  
  110.         {  
  111.             webDriver.FindElement(ControlProperties.city).Clear();  
  112.             webDriver.FindElement(ControlProperties.city).SendKeys(userCity);  
  113.             WaitTime();  
  114.         }  
  115.   
  116.         public void SecurityQuestion(string userSecurityQuestion)  
  117.         {  
  118.             IWebElement securityQues = webDriver.FindElement(ControlProperties.securityQuestion);  
  119.             securityQues.Click();  
  120.             Thread.Sleep(3000);  
  121.             SelectElement select = new SelectElement(securityQues);  
  122.             select.SelectByValue(userSecurityQuestion);  
  123.             WaitTime();  
  124.         }  
  125.   
  126.         public void SecurityAnswer(string userSecurityAnswer)  
  127.         {  
  128.             webDriver.FindElement(ControlProperties.securityAnswer).Clear();  
  129.             webDriver.FindElement(ControlProperties.securityAnswer).SendKeys(userSecurityAnswer);  
  130.             WaitTime();  
  131.         }  
  132.   
  133.         public void Captcha()  
  134.         {  
  135.             //Selenium doesn't support automation of Captcha, we need to automate it using Third party dll's.  
  136.         }  
  137.   
  138.         public void SendUpdates()  
  139.         {  
  140.             webDriver.FindElement(ControlProperties.sendMeUpdates).Click();  
  141.             WaitTime();  
  142.         }  
  143.   
  144.         public void IAcceptTerms()  
  145.         {  
  146.             webDriver.FindElement(ControlProperties.iAccept).Click();  
  147.             WaitTime();  
  148.         }  
  149.   
  150.         public void RegisterMe()  
  151.         {  
  152.             webDriver.FindElement(ControlProperties.registerMe).Click();  
  153.             WaitTime();  
  154.         }  
  155.   
  156.         public void HomeClick()  
  157.         {  
  158.             webDriver.FindElement(ControlProperties.homeClick).Click();  
  159.             WaitTime();  
  160.         }  
  161.   
  162.         public void SearchClick()  
  163.         {  
  164.             webDriver.FindElement(ControlProperties.searchClick).Click();  
  165.             WaitTime();  
  166.         }  
  167.   
  168.         public void AuthorSearchClick()  
  169.         {  
  170.             webDriver.FindElement(ControlProperties.authorSearchClick).Click();  
  171.             WaitTime();  
  172.         }  
  173.   
  174.         public void AuthorFirstName(string userFirstName)  
  175.         {  
  176.             webDriver.FindElement(ControlProperties.authorFirstName).Clear();  
  177.             webDriver.FindElement(ControlProperties.authorFirstName).SendKeys(userFirstName);  
  178.             WaitTime();  
  179.         }  
  180.   
  181.         public void AuthorSearchButton()  
  182.         {  
  183.             webDriver.FindElement(ControlProperties.searchBtn).Click();  
  184.             Thread.Sleep(3000);  
  185.             WaitTime();  
  186.         }  
  187.   
  188.         public void ProfileClick()  
  189.         {  
  190.             webDriver.FindElement(ControlProperties.profileClick).Click();  
  191.             WaitTime();  
  192.         }  
  193.   
  194.         public void ArticlesClick()  
  195.         {  
  196.             webDriver.FindElement(ControlProperties.articlesClick).Click();  
  197.             WaitTime();  
  198.         }  
  199.   
  200.   
  201.         public void FirstArticleClick()  
  202.         {  
  203.             webDriver.FindElement(ControlProperties.firstArticleClick).Click();  
  204.             WaitTime();  
  205.         }  
  206.   
  207.         public void WaitTime()  
  208.         {  
  209.             WebDriverWait webDriverWait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(10));  
  210.         }  
  211.     }  
  212.   
  213.     [TestClass]  
  214.     public class DriverInitialization  
  215.     {  
  216.         IWebDriver Webdriver;  
  217.   
  218.         public DriverInitialization()  
  219.         {  
  220.             ChromeOptions chromeOptions = new ChromeOptions();  
  221.             chromeOptions.AddArgument("disable-infobars");  
  222.             Webdriver = new ChromeDriver(@"D:\chromedriver_win32", chromeOptions);  
  223.             Webdriver.Navigate().GoToUrl("https://www.c-sharpcorner.com/");  
  224.             Webdriver.Manage().Window.Maximize();  
  225.             WebDriverWait webDriverWait = new WebDriverWait(Webdriver, TimeSpan.FromSeconds(40));  
  226.         }  
  227.   
  228.         [TestMethod]  
  229.         public void UserRegisteration()  
  230.         {  
  231.             // Four User Login Data.  
  232.             PageObjectModelMethods register = new PageObjectModelMethods(Webdriver);  
  233.             register.SignUpClick();  
  234.             register.EnterEmail("Khaja.moiz@gmail.com");  
  235.             register.FirstName("Khaja");  
  236.             register.LastName("Moizuddin");  
  237.             register.Password("1234567890");  
  238.             register.ConfirmPassword("1234567890");  
  239.             register.CountryDopDown("India");  
  240.             register.ZipCode("500076");  
  241.             register.City("Hyderabad");  
  242.             register.SecurityQuestion("2");  
  243.             register.SecurityAnswer("Valuemomentum Software Services");  
  244.             register.SendUpdates();  
  245.             register.IAcceptTerms();  
  246.             register.RegisterMe();  
  247.             register.HomeClick();  
  248.             register.SearchClick();  
  249.             register.AuthorSearchClick();  
  250.             register.AuthorFirstName("Khaja");  
  251.             register.AuthorSearchButton();  
  252.             register.ProfileClick();  
  253.             register.ArticlesClick();  
  254.             register.FirstArticleClick();  
  255.             Webdriver.Quit();  
  256.         }  
  257.     }  
  258. }  
In the above program I am performing the automation on the C# Corner signup page with the help of Page Object Model design pattern. I have used control properties static class for declaring all the control properties related to C# Corner sign up page. 
 
Similarly, in PageObjectModelMethods class, I am accessing Webdriver which I am passing from DriverInitialization class, userRegisteration() method.
 
In PageObjectModelMethods class I have the functionality of all the controls available in C# Corner signup page by accessing ControlProperties static class variables like below.
  1. public void SignUpClick() {  
  2.     webDriver.FindElement(ControlProperties.signupClick).Click();  
  3.     WaitTime();  
  4. }  
  5. public void EnterEmail(string userEmail) {  
  6.     webDriver.FindElement(ControlProperties.email).Clear();  
  7.     webDriver.FindElement(ControlProperties.email).SendKeys(userEmail);  
  8.     WaitTime();  
  9. }  
  10. public void FirstName(string userFirstName) {  
  11.     webDriver.FindElement(ControlProperties.firstName).Clear();  
  12.     webDriver.FindElement(ControlProperties.firstName).SendKeys(userFirstName);  
  13.     WaitTime();  
  14. }  
  15. public void LastName(string userLastName) {  
  16.     webDriver.FindElement(ControlProperties.lastName).Clear();  
  17.     webDriver.FindElement(ControlProperties.lastName).SendKeys(userLastName);  
  18.     WaitTime();  
  19. }  
In the above code once the webpage is navigated to C# Corner's home page I am performing a click on SignUp button by accessing the static class variable such as ControlProperties.SignupClick which contains the control's unique property. I am finding the control with FindElement() method and once the element is identified I am clicking on the control. Here I am performing waitTime for a control by using WebDriverWait class.
 
Similarly, for entering Email control, I am accessing the value as ControlProperties.email and finding the control with FindElement() method.
 
Once the element is identified, I am clearing the control if any value exists with Clear() method and performing SendKeys with the provided value.
 
Similarly, for FirstName and LastName, I am accessing the value from static ControlProperties class such as ControlProperties.firstName and ControlProperties.lastName and performing clear() and SendKeys() to the control.
  1. public void Password(string userPassword) {  
  2.     webDriver.FindElement(ControlProperties.password).Clear();  
  3.     webDriver.FindElement(ControlProperties.password).SendKeys(userPassword);  
  4.     WaitTime();  
  5. }  
  6. public void ConfirmPassword(string userConfirmPassword) {  
  7.     webDriver.FindElement(ControlProperties.confirmPassword).Clear();  
  8.     webDriver.FindElement(ControlProperties.confirmPassword).SendKeys(userConfirmPassword);  
  9.     WaitTime();  
  10. }  
  11. public void CountryDopDown(string countryName) {  
  12.     IWebElement countryDrop = webDriver.FindElement(ControlProperties.countryDropdown);  
  13.     countryDrop.Click();  
  14.     SelectElement select = new SelectElement(countryDrop);  
  15.     select.SelectByValue(countryName);  
  16.     WaitTime();  
  17. }  
  18. public void ZipCode(string userZipCode) {  
  19.     webDriver.FindElement(ControlProperties.zipCode).Clear();  
  20.     webDriver.FindElement(ControlProperties.zipCode).SendKeys(userZipCode);  
  21.     WaitTime();  
In the above code, in order to automate the Password, ConfirmPassword, CountryDropDown, and ZipCode, I have used the above methods. For each method, I am accessing the static variable which is declared inside the static ControlProperties class which has the control's unique property.
 
Once the control is identified, I am clearing the control with Clear/() method and entering the provided value using SendKeys() method.
  1. public void City(string userCity) {  
  2.     webDriver.FindElement(ControlProperties.city).Clear();  
  3.     webDriver.FindElement(ControlProperties.city).SendKeys(userCity);  
  4.     WaitTime();  
  5. }  
  6. public void SecurityQuestion(string userSecurityQuestion) {  
  7.     IWebElement securityQues = webDriver.FindElement(ControlProperties.securityQuestion);  
  8.     securityQues.Click();  
  9.     Thread.Sleep(3000);  
  10.     SelectElement select = new SelectElement(securityQues);  
  11.     select.SelectByValue(userSecurityQuestion);  
  12.     WaitTime();  
  13. }  
  14. public void SecurityAnswer(string userSecurityAnswer) {  
  15.     webDriver.FindElement(ControlProperties.securityAnswer).Clear();  
  16.     webDriver.FindElement(ControlProperties.securityAnswer).SendKeys(userSecurityAnswer);  
  17.     WaitTime();  
  18. }  
  19. public void Captcha() {  
  20.     //Selenium doesn't support automation of Captcha, we need to automate it using Third party dll's.  
  21. }  
  22. public void SendUpdates() {  
  23.     webDriver.FindElement(ControlProperties.sendMeUpdates).Click();  
  24.     WaitTime();  
  25. }  
  26. public void IAcceptTerms() {  
  27.     webDriver.FindElement(ControlProperties.iAccept).Click();  
  28.     WaitTime();  
  29. }  
  30. public void RegisterMe() {  
  31.     webDriver.FindElement(ControlProperties.registerMe).Click();  
  32.     WaitTime();  
In the above code for City, SecurityAnswer, I am doing the same thing I did for earlier controls. For securityQuestion, I am accessing the control property from static class ControlProperties. Once the control property is identified, I am passing IWebElement object reference to SelectElement class as a parameter. Once the list of values is identified, I am finding it with the given value.
 
Captcha controls cannot be automated with Selenium directly which uses some third party dll. SendUpdates and I Accept Terms are two checkboxes which can be clicked by using Click() method.
  1. public void HomeClick() {  
  2.     webDriver.FindElement(ControlProperties.homeClick).Click();  
  3.     WaitTime();  
  4. }  
  5. public void SearchClick() {  
  6.     webDriver.FindElement(ControlProperties.searchClick).Click();  
  7.     WaitTime();  
  8. }  
  9. public void AuthorSearchClick() {  
  10.     webDriver.FindElement(ControlProperties.authorSearchClick).Click();  
  11.     WaitTime();  
  12. }  
  13. public void AuthorFirstName(string userFirstName) {  
  14.     webDriver.FindElement(ControlProperties.authorFirstName).Clear();  
  15.     webDriver.FindElement(ControlProperties.authorFirstName).SendKeys(userFirstName);  
  16.     WaitTime();  
  17. }  
  18. public void AuthorSearchButton() {  
  19.     webDriver.FindElement(ControlProperties.searchBtn).Click();  
  20.     Thread.Sleep(3000);  
  21.     WaitTime();  
  22. }  
  23. public void ProfileClick() {  
  24.     webDriver.FindElement(ControlProperties.profileClick).Click();  
  25.     WaitTime();  
  26. }  
  27. public void ArticlesClick() {  
  28.     webDriver.FindElement(ControlProperties.articlesClick).Click();  
  29.     WaitTime();  
  30. }  
  31. public void FirstArticleClick() {  
  32.     webDriver.FindElement(ControlProperties.firstArticleClick).Click();  
  33.     WaitTime();  
  34. }  
  35. public void WaitTime() {  
  36.     WebDriverWait webDriverWait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(10));  
  37. }  
From the above code, once the registration automation is done, I am clicking on the home button; then clicking on search button which is available on the top right. Once we will have two tabs that are Content and People. I am clicking on the People tab and giving the FirstName as provided by the user and clicking on the Search button. Once the author's profile is highlighted, I am clicking on the author's profile and clicking on Articles Link which displays a list of articles from those I am clicking on the First article which is available on the top.
  1. public class DriverInitialization {  
  2.     IWebDriver Webdriver;  
  3.     public DriverInitialization() {  
  4.             ChromeOptions chromeOptions = new ChromeOptions();  
  5.             chromeOptions.AddArgument("disable-infobars");  
  6.             Webdriver = new ChromeDriver(@ "D:\chromedriver_win32", chromeOptions);  
  7.             Webdriver.Navigate().GoToUrl("https://www.c-sharpcorner.com/");  
  8.             Webdriver.Manage().Window.Maximize();  
  9.             WebDriverWait webDriverWait = new WebDriverWait(Webdriver, TimeSpan.FromSeconds(40));  
  10.         }  
  11.         [TestMethod]  
  12.     public void UserRegisteration() {  
  13.         // Four User Login Data.  
  14.         PageObjectModelMethods register = new PageObjectModelMethods(Webdriver);  
  15.         register.SignUpClick();  
  16.         register.EnterEmail("Khaja.moiz@gmail.com");  
  17.         register.FirstName("Khaja");  
  18.         register.LastName("Moizuddin");  
  19.         register.Password("1234567890");  
  20.         register.ConfirmPassword("1234567890");  
  21.         register.CountryDopDown("India");  
  22.         register.ZipCode("500076");  
  23.         register.City("Hyderabad");  
  24.         register.SecurityQuestion("2");  
  25.         register.SecurityAnswer("Valuemomentum Software Services");  
  26.         register.SendUpdates();  
  27.         register.IAcceptTerms();  
  28.         register.RegisterMe();  
  29.         register.HomeClick();  
  30.         register.SearchClick();  
  31.         register.AuthorSearchClick();  
  32.         register.AuthorFirstName("Khaja");  
  33.         register.AuthorSearchButton();  
  34.         register.ProfileClick();  
  35.         register.ArticlesClick();  
  36.         register.FirstArticleClick();  
  37.         Webdriver.Quit();  
  38.     }  
  39. }   
From the above code in DriverIntialization class i am using DriverIntialization constructor for intializing the  chrome driver by passing the chrome driver exe path and navigating to the C# Corner website and maximizing it using Maximize() method.   
 
In UserRegisterationMethod() I am passing the web driver from PageObjectModelMethods class initialization of a class. This PageObjectModelMethods is assigning the web driver to its local Webdriver as Webdriver= webdriver; and, it can be accessed by all the methods inside the PageObjectModelMethods class.
 
Once the PageObjectModelMethods are initialized with the webdriver, I am calling each method of a PageObjectModelMethods class by using its reference variable as shown in the above code.
 
Conclusion
 
The use of the Page Object Model is that if any of the control properties or value is changed then we can change the value by going to the respective class without disturbing the other Classes or Methods.
 
With this design pattern approach, we can reduce code duplication and complexity and increases reusability and easy maintenance of code.
 
Thanks & I hope this helps you.