Skip to main content

Creating a fully functional page object model automation framework with Selenium in 1 hour

In this tutorial we will check how to create a simple Selenium/ Testng page object model framework with reporting and logging capabilities.

For this I'm using Intellij idea IDE Community version because of its amazing debugging capabilities. Also I'm using Maven, Selenium with Testng with log4j.



Let's begin,

1. Create a Maven project using intellij IDE.







2. Prepare the project structure as follows,

There should be 4 folders/packages to handle functions, pages, resources and test cases.  Before that delete the existing auto org.example folders in both main and test folders. Then created following folders as below.



3. Now we need to download all the necessary packages we need to use in this project. Paste following mvn dependencies in your pom.xml file within <dependencies></dependencies> tags.


before that remove this junit dependency which is already coming automatically because we don't need it.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>


Now lets add following dependencies 

<dependencies>
<!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.3.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.7.1</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.19.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>

  


In here we are using webdriver manager. What it does is, it manages webdriver versions and download the relevant webdriver according to our current browser. So we don't need to worry about the Webdriver version. 

Next is testng, testng handles the assertions in our framework.


Log4j handles the logging of our automation suite, once we deploy it in a CI/CD server like jenkins we can go to the relevant log and check why it got failed. This makes easy to debug.


4. Now lets create BaseClass.java in resources package. Paste the following code, this will handle the browser setting up part.

package resources;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;


public class BaseClass {
WebDriver driver;

String url = "https://www.saucedemo.com/";
//Initialize the driver
public WebDriver initializeDriver(){
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.navigate().to(url);
driver.manage().window().maximize();
return driver;
}

}



ok, I forgot to mention what we are automating ðŸ™‚ We are automating this https://www.saucedemo.com/ website.


5. Basic principle in Page Object Model is Pages and test cases should be in separate. So we will create Page class and get the relevant xpaths as follows,

package pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage {
public WebDriver driver;

By txt_username = By.xpath("//input[@id='user-name']");
By txt_password = By.xpath("//input[@id='password']");
By btn_login = By.xpath("//input[@id='login-button']");
By lbl_UsrNameRequired = By.xpath("//h3[text()='Epic sadface:
Username is required']");
By lbl_UsrNamePassNotMatched = By.xpath("//h3[text()='Epic sadface:
Username and password do not match any user in this service']");
By lbl_PassRequired = By.xpath("//h3[text()='Epic sadface:
Password is required']");

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

public void enterUserName(){
driver.findElement(txt_username).sendKeys("standard_user");
}

public void enterPassword(){
driver.findElement(txt_password).sendKeys("secret_sauce");
}

public void clickLoginBtn(){
driver.findElement(btn_login).click();
}

public String getLblUsrNameRequired(){
return driver.findElement(lbl_UsrNameRequired).getText();
}

public String getLblPassRequired(){
return driver.findElement(lbl_PassRequired).getText();
}

public String getUsrPassNotMatched(){
return driver.findElement(lbl_UsrNamePassNotMatched).getText();
}

}


I hope you already have knowledge on how to capture xpaths. If you need to know how to capture xpaths i suggest you to read this tutorial on xpaths.

6. For the simplicity we will implement its relevant functions in our functions package, so pages to functions logics in separate locations. This will help if a certain page that we need to automate has hundreds of web elements, that class will be get so many lines and it will be hard to read that code.

package functions;

import org.openqa.selenium.WebDriver;
import pages.LoginPage;

public class LoginPageFunctions {
WebDriver driver;
LoginPage lp;

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

public void loginToPortal(){
lp = new LoginPage(driver);
lp.enterUserName();
lp.enterPassword();
lp.clickLoginBtn();
}

public void loginToPortalWithOutPass(){
lp = new LoginPage(driver);
lp.enterUserName();
lp.clickLoginBtn();
}

public void loginToPortalWithOutUsrNm(){
lp = new LoginPage(driver);
lp.enterPassword();
lp.clickLoginBtn();
}

public void loginToPortalUsrPassNotMatched(){
lp = new LoginPage(driver);
lp.enterUserName();
lp.enterPassword();
}



public String getUsrNameRequired(){
return lp.getLblUsrNameRequired();
}

public String getPassRequired(){
return lp.getLblPassRequired();
}

public String getUsrPassNotMatched(){
return lp.getUsrPassNotMatched();
}



}



7.  Now lets write the test cases in our testcases package.


 For this we will be creating test cases to validate the login for this application

  1.   Validate whether user can log in to the application successfully.
  2.   Validate when trying to log in without password, it displays the expected message.
  3.   Validate when trying to log in without username, it displays the expected message.

package testcases;

import functions.LoginPageFunctions;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import pages.InventoryPage;
import resources.BaseClass;


public class LoginPageTests extends BaseClass {
WebDriver driver;
LoginPageFunctions lpf;
InventoryPage ip;



@BeforeMethod
public void initialize(){
driver = initializeDriver();
}

@Test(priority = 0)
public void checkLoginSuccessful(){
lpf = new LoginPageFunctions(driver);
lpf.loginToPortal();
ip = new InventoryPage(driver);
Assert.assertEquals(ip.getInventoryPgeLabel(),"Products"," User
did not logged in to the system");
}

@Test(priority=1)
public void checkPasswordRequiredMessage(){
lpf = new LoginPageFunctions(driver);
lpf.loginToPortalWithOutPass();
Assert.assertEquals(lpf.getPassRequired(),"Epic sadface:
Password is required","Password required message not visible");
}

@Test(priority = 2)
public void checkUserNameRequiredMessage(){
lpf = new LoginPageFunctions(driver);
lpf.loginToPortalWithOutUsrNm();
Assert.assertEquals(lpf.getUsrNameRequired(),"Epic sadface:
Username is required","Username required message not visible");
}




@AfterMethod
public void tearDown(){
driver.close();
}


}



8. Lets try executing one test case. You can run multiple by right click > Run 'LoginPageTests'



This should work ðŸ™‚



9. Now let's implement logging capability to our automation suite. For this we need to have log4j2.xml configuration file in our resources package.


log4j2.xml


<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="basePath">./logs</Property>
</Properties>

<Appenders>
<RollingFile name="File" fileName="${basePath}/prints.log"
filePattern="${basePath}/prints-%d{yyyy-MM-dd}.log">
<PatternLayout pattern=
"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>



10. Now in order to use log4j in our project, you need to implement following function in our BaseClass.java file.


//setting up log4j configuration file location
public void log4jConfigPathSetup() {
Configurator.initialize(null,System.getProperty("user.dir")+
"/src/main/java/resources/log4j2.xml");
}


at the end, your BaseClass.java file should look like this.


package resources;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.apache.logging.log4j.core.config.Configurator;

public class BaseClass {
WebDriver driver;

String url = "https://www.saucedemo.com/";
//Initialize the driver
public WebDriver initializeDriver(){
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.navigate().to(url);
driver.manage().window().maximize();
return driver;
}

//setting up log4j configuration file location
public void log4jConfigPathSetup() {
Configurator.initialize(null,System.getProperty("user.dir")+
"/src/main/java/resources/log4j2.xml");
}
}


So every time when you need to use log4j inside you test cases, you have to do the following, i will add

fully log4j implemented class.

package testcases;

import functions.LoginPageFunctions;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import pages.InventoryPage;
import resources.BaseClass;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LoginPageTests extends BaseClass {
WebDriver driver;
LoginPageFunctions lpf;
InventoryPage ip;
public static Logger log = LogManager.getLogger(LoginPageTests.class);


@BeforeMethod
public void initialize(){
driver = initializeDriver();
log4jConfigPathSetup();
}

@Test(priority = 0)
public void checkLoginSuccessful(){
lpf = new LoginPageFunctions(driver);
lpf.loginToPortal();
ip = new InventoryPage(driver);
log.info("TC001: check login successful");
Assert.assertEquals(ip.getInventoryPgeLabel(),
"Products"," User did not logged in to the system");
}

@Test(priority=1)
public void checkPasswordRequiredMessage(){
lpf = new LoginPageFunctions(driver);
lpf.loginToPortalWithOutPass();
log.info("TC002: check password required message");
Assert.assertEquals(lpf.getPassRequired(),
"Epic sadface: Password is required","Password required message not visible");
}

@Test(priority = 2)
public void checkUserNameRequiredMessage(){
lpf = new LoginPageFunctions(driver);
lpf.loginToPortalWithOutUsrNm();
log.info("TC002: check Username required message");
Assert.assertEquals(lpf.getUsrNameRequired(),
"Epic sadface: Username is required","Username required message not visible");
}



@AfterMethod
public void tearDown(){
driver.close();
}


}




Now do one more execution and reload your entire project, you will see an automatically created logs folder with the log :)








Thanks a lot for your time, That didn't even took more than 45 minutes, right? ðŸ˜‡ .



Github repo: https://github.com/iroshanAV/simple-pom





 

Comments

Popular posts from this blog

Creating fully functional page object model automation framework with Playwright in 1 hour

 We are back with another 1hour tutorial  😇 . This time we will be creating Playwright and Typescript page object model framework. For this we will be using Visual Studio Code editor. Hope you have a basic idea on Playwright. There are plenty of resources you can refer to get the basic idea of the Playwright. In this tutorial we will be focussing more on how to implement Page Object model in Playwright. So let's begin. Before all of this, you must need to have  node js  installed. I hope you have already done that. 1. Download the relevant nodejs packages by using following command  npm init playwright@latest 2. Lets create our project structure. Unlike Selenium 1 hour lesson for this we will be creating just two folders. To write page objects we use "pages" folder and to write tests we create "tests" folder. Just for now, run the default tests which Playwright automatically create with its installation. use  npx playwright test command in your CMD. By de...

How to create Push Notification System for your Cordova app with OneSignal and Firebase

H ello Everyone, today i'm going to show you how to add push notification system for your Cordova mobile app with OneSignal. First let's talk little bit about OneSignal. OneSignal is a multi-platform push notification service, which gives you variety of features. It lets you to send push notifications to almost all current mobile Operating Systems. You can check out their documentation if you want or start straightly this tutorial. If you need to see the project structure  and stuff  go to github repo Lets begin our tutorial 😎😎😎 First lets create a Cordova project. type following command in your CMD.    C:\Users\acer>cordova create push There will be a structure like this,      Now run android emulator, if you don't know how to run emulator from your CMD see this tutorial and do it exactly like that. Go to your project folder and then type the following command in your CMD  C:\Users\acer\push>cordova platfor...

How to deploy Android Emulator from CMD in Windows

First go to your C drive Then find Users folder and your Personal folder in my case acer Then go to .android folder Now first you have to check what are the available emulators first emulator -list-avds you will get some thing like this, if not you have to create emulator device first .  Now run following command by specifying which device you want. For me i will pick Nexus_5_API_24 emulator -avd Nexus_5_API_24 And your job is done.