Filter by tags:
August 8, 2022
- TestNG Assert.assertEquals compares the two strings
- This is one of situvations we get java.lang.AssertionError when the strings are not equal
- For instance,
String expectedEditProductURL = "http://sadakar.website.lab/Product?productId=89";
String actualEditProductURL = driver.getCurrentUrl();
Assert.assertEquals(actualEditProductURL, expectedEditProductURL);
java.lang.AssertionError: http://sadakar.website.lab/Product?productId=89 expected [http://sadakar.website.lab/Product?productId=899] but found [Change Product details hyperlink clicking is failed]
at org.testng.Assert.fail(Assert.java:97)
at org.testng.Assert.assertEqualsImpl(Assert.java:136)
at org.testng.Assert.assertEquals(Assert.java:118)
at org.testng.Assert.assertEquals(Assert.java:575)
August 8, 2022
io.cucumber.testng.UndefinedStepException
- This exception, normally observed when the the steps are undefined.
- I have had two scenario's with same name and same tag provided then the one that has glue code defined is PASSED and the other is FAILED.
- Generally, we don't give the same scenario name.
PASSED: runScenario("Validating navigation to Products Page", "Optional[Product page validations]")
FAILED: runScenario("Validating navigation to Products Page", "Optional[Product page validations]")
io.cucumber.testng.UndefinedStepException: The step 'Clicks on Edit Product Hyperlink' and 1 other step(s) are undefined.
You can implement these steps using the snippet(s) below:
@Then("Clicks on Edit Product Hyperlink")
public void clicks_on_edit_route_overrides_hyperlink() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
@Then("Verifies the navigation to Product Edit Page")
public void verifies_the_navigation_to_trading_partner_route_overrides_page() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
at io.cucumber.core.runtime.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:69)
at io.cucumber.testng.TestCaseResultObserver.assertTestCasePassed(TestCaseResultObserver.java:23)
at io.cucumber.testng.TestNGCucumberRunner.lambda$runScenario$1(TestNGCucumberRunner.java:133)
at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$3(CucumberExecutionContext.java:110)
at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:110)
at io.cucumber.testng.TestNGCucumberRunner.runScenario(TestNGCucumberRunner.java:129)
at io.cucumber.testng.AbstractTestNGCucumberTests.runScenario(AbstractTestNGCucumberTests.java:35)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:134)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:597)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:816)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.testng.TestRunner.privateRun(TestRunner.java:766)
at org.testng.TestRunner.run(TestRunner.java:587)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1187)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1109)
at org.testng.TestNG.runSuites(TestNG.java:1039)
at org.testng.TestNG.run(TestNG.java:1007)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
August 8, 2022
August 7, 2022
org.openqa.selenium.StaleElementReferenceException
( JasperSoft BI Suite Tutorials - Sadakar Pochampalli )
org.openqa.selenium.StaleElementReferenceException
When it occurs ?
- When the element has been deleted entirely.
- When the element is no longer attached to the DOM
Causes:
- When the page is refreshed
- When the user is navigated to another page
- When the java script deletes the element and creates the same element with the same id then the driver may not identify the replacement
How to overcome ?
- By refreshing the web page |
driver.findElement(By.xpath("xpath")).click();
- By using Try Catch Block
- By using ExpectedConditions.refreshed
wait.until(ExpectedConditions.refreshed(ExpectedConditions.stalenessOf("ThisIsElement");
- By using POM Lazy Initialization
- In POM, we use initElements() method which loads the element but it won’t initialize elements.
- initElements() takes latest address.
- It initializes during run time when we try to perform any action on an element.
- This process is also known as Lazy Initialization.
August 7, 2022
org.openqa.selenium.NoSuchElementException
- Thrown by various accessor methods to indicate that the element being requested does not exist.
- If the element is not present on the DOM, we get NoSuchElementException Exception
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="TablePartners"]/tbody/tr/td[4]/a[1]"}
(Session info: chrome=103.0.5060.134)
For documentation on this error, please visit: https://selenium.dev/exceptions/#no_such_element
Build info: version: '4.3.0', revision: 'a4995e2c09*'
System info: host: 'SADAKARP', ip: '100.200.1.3', os.name: 'Windows 11', os.arch: 'amd64', os.version: '10.0', java.version: '17.0.3'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [108db81f036e7466c1939f054decbfb8, findElement {using=xpath, value=//*[@id="TablePartners"]/tbody/tr/td[4]/a[1]}]
Capabilities {acceptInsecureCerts: true, browserName: chrome, browserVersion: 103.0.5060.134, chrome: {chromedriverVersion: 103.0.5060.53 (a1711811edd7..., userDataDir: C:\Users\sadakarp\AppData\L...}, goog:chromeOptions: {debuggerAddress: localhost:61571}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: WINDOWS, proxy: Proxy(), se:cdp: ws://localhost:61571/devtoo..., se:cdpVersion: 103.0.5060.134, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
Session ID: 108db81f036e7466c1939f054decbfb8
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:200)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:133)
at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:53)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:184)
at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:167)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:142)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:569)
at org.openqa.selenium.remote.ElementLocation$ElementFinder$2.findElement(ElementLocation.java:162)
at org.openqa.selenium.remote.ElementLocation.findElement(ElementLocation.java:60)
at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:387)
at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:379)
at com.inovalon.cucumber.stepdef.tradingpartners.AddTradingPartner.search_for_the_Trading_Partner_created_and_verify_for_its_existance(AddTradingPartner.java:107)
at ✽.Search for the Trading Partner created and verify for its existance(classpath:features/AddTradingPartner.feature:19)
August 7, 2022
August 5, 2022
org.openqa.selenium.TimeoutException
- Thrown when a command does not complete in enough time.
- For instance, in the below example, we get TimeOutException after having waited for 30 seconds
- This is an explicit wait technique in selenium and the element is identified using method visibilityOfElementLocated in the DOM(Document Object Model)
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a[contains(text(),'Add New Partner')]")));
org.openqa.selenium.TimeoutException: Expected condition failed: waiting for visibility of element located by By.xpath: //a[contains(text(),'Add New Partner')] (tried for 30 second(s) with 500 milliseconds interval)
Build info: version: '4.3.0', revision: 'a4995e2c09*'
System info: host: 'SADAKARP', ip: '392.100.7.2', os.name: 'Windows 11', os.arch: 'amd64', os.version: '10.0', java.version: '17.0.3'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptInsecureCerts: true, browserName: chrome, browserVersion: 103.0.5060.134, chrome: {chromedriverVersion: 103.0.5060.53 (a1711811edd7..., userDataDir: C:\Users\sadakarp\AppData\L...}, goog:chromeOptions: {debuggerAddress: localhost:60618}, networkConnectionEnabled: false, pageLoadStrategy: none, platformName: WINDOWS, proxy: Proxy(), se:cdp: ws://localhost:60618/devtoo..., se:cdpVersion: 103.0.5060.134, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
Session ID: c13c1f6304ded0dc6587693ac3eae3b6
at org.openqa.selenium.support.ui.WebDriverWait.timeoutException(WebDriverWait.java:87)
at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:231)
August 5, 2022
August 2, 2022
Cross tab + Graph --> Extra blank page issue in jasper reports
( JasperSoft BI Suite Tutorials - Sadakar Pochampalli )
https://community.jaspersoft.com/questions/513786/blank-page-end
August 2, 2022
Screenshots in Selenium with Cucumber, TestNG
( JasperSoft BI Suite Tutorials - Sadakar Pochampalli )
Screenshots in Selenium with Cucumber, TestNG
- Purpose: To analyze or de-bug or trace the test execution (or to analyze a bug)
- Generally, used with failed scenarios/tests
- Very handy when executing tests in Non GUI environments such as Jenkins, AzureDevOps and etc.
- In cucumber, write the screenshots code in After hook
- Ensure to quit the driver immediately after taking the screenshot
- If screenshot and quit has to go in two different methods use order for the After hook.
- For instance, give order=0 for quit the driver and give order=1 to take the screenshot.
Example
Screenshot is implemented based on my previous example on page factory codebase.
Refer this post on page factory and in the Hooks.java class update the code of After hooks namely
@After(order=0) and @After(order=1)
Refer this post on page factory and in the Hooks.java class update the code of After hooks namely
@After(order=0) and @After(order=1)
Download Screenshots source code from GitHub OR
click this to download as a Zip
- In the order=0 After hook section, quit the driver and in the order=1 hook section take the screenshot.
- Use the attach method of scenario object
(NOTE: This example is based on io.cucumber 7.1.0 and it doesn't support embed method) - isFailed() identifies the failed scenario , for instance in the DirectoryPageFactory.java file (refer the code from previous example above) xpath for the searchButtonLocator is deliberately updated to a bad entry so this produces an error in validation.
// Search button locator
@FindBy(xpath = "//*[@id=\"searchBtnBAD\"]")
public WebElement searchButtonLocator;
package com.sadakar.common;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
public class Hooks extends BasePage {
@Before //Cucumber Before Hook
public void setupDriver() throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://opensource-demo.orangehrmlive.com/index.php/auth/login");
}
@After(order=0) // Cucumber After hook with order 0
public void quitDriver() throws Exception {
driver.quit();
}
@After(order = 1) // Cucumber After Hook with order 1
public void takeScreenShotOnFailedScenario(Scenario scenario) {
System.out.println("This is from After hook, order=1");
if ((scenario.isFailed())) {
final byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", scenario.getName());
}
}
}
Where does screenshots get stored ?
The code above is a cucumber based screenshot in the Hooks so eventually the screenshots get stored in the cucumber related reports.For instance, below is the cucumber report folder in the target
As the cucumberreport.html is opened, we can see the screenshot appended at the end of the scenario.
What if the order of After hooks for quit is 1 and
for screenshot is 0
We end up with the following error message:
org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
Build info: version: '4.3.0', revision: 'a4995e2c09*'
System info: host: 'SADAKARP', ip: '136.144.2.8', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '16.0.2'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Command: [null, screenshot {}]
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 103.0.5060.134, chrome: {chromedriverVersion: 103.0.5060.53 (a1711811edd7..., userDataDir: C:\Users\sadakarp\AppData\L...}, goog:chromeOptions: {debuggerAddress: localhost:64648}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: WINDOWS, proxy: Proxy(), se:cdp: ws://localhost:64648/devtoo..., se:cdpVersion: 103.0.5060.134, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:145)
at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:167)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:142)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:569)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:624)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:628)
at org.openqa.selenium.remote.RemoteWebDriver.getScreenshotAs(RemoteWebDriver.java:353)
at com.sadakar.common.Hooks.takeScreenShotOnFailedScenario(Hooks.java:29)
August 2, 2022
August 1, 2022
How to use TestNG BeforeSuite and AfterSuite Hooks for connecting and closing ms sql database in Se…
( JasperSoft BI Suite Tutorials - Sadakar Pochampalli )
In this post, we will see, how to create a database connection only once and how to close the connection once using TestNG BeforeSuite and AfterSuite annotations.
@BeforeSuite
- The method that is annotated with BeforeSuite will run after all scenarios or tests.
- That is BeforeSuite will be executed only once before executing all scenarios or tests.
@AfterSuite
- The method that is annotated with AfterSuite will run after all scenarios or tests.
- That is AfterSuite will be executed only once after executing all scenarios or tests.
Example:
Connect to MS-SQL server in Selenium with Cucumber and TestNG project only once to perform database operations.
DatabaseHooks.java
@BeforeHook
- Create the connection before executing all the cucumber scenarios.
- In the code below, ff the connection is null then establish the connection and if
the connection is not null then print a message saying that the connection is already created.
@AfterHook
- Close the connection after executing all the cucumber scenarios.
package com.sadakar.cucumber.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
public class DatabaseHooks {
// Connection object
private static Connection dbConn = null;
// Statement object
@SuppressWarnings("unused")
private static Statement stmt;
// Constant for Database URL
public static String DB_URL = "jdbc:sqlserver://14.456.9.20:1433;user=TestUser;password=TestPassWord;database=TestDB";
@BeforeSuite //TestNG annotation
public static Connection getDBConnection() {
try {
if (dbConn == null) {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
dbConn = DriverManager.getConnection(DB_URL);
System.out.println("Connected to Database - BeforeSuite TestNG");
}
else {
System.out.println("Already Connected to Database - BeforeSuite TestNG");
}
} catch (Exception e) {
e.printStackTrace();
}
return dbConn;
}
@AfterSuite //TestNG
public static void closeConnection() {
if (dbConn != null)
try {
dbConn.close();
System.out.println("Database connection closed - AfterSuite TestNG");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
CreateUser.java
- Create a Connection Object in the CreateUser class.
- Create Statement(s) and execute and store the result in res1 variable of ResultSet
- Connection for the database is created once in the above Hook and we are using it in
CreateUser class and similarly, we can make use of the same connection in other classes.
package com.sadakar.cucumber.stepdefinitions;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Duration;
import java.util.List;
import org.openqa.selenium.By;
import org.testng.Assert;
import com.sadakar.cucumber.common.DatabaseHooks;
import com.sadakar.resource.utilities.Log;
import com.sadakar.webui.common.BasePage;
import io.cucumber.java.en.Then;
public class CreateUser extends BasePage {
Connection con = DatabaseHooks.getDBConnection();
@Then("Fills the user on the User form")
public void fillTheUserFrom(io.cucumber.datatable.DataTable dataTableAddUser)
throws InterruptedException, SQLException {
if (dataTableAddUser == null)
throw new NullPointerException("cells can not be null");
List<List<String>> cells = dataTableAddUser.cells();
Statement sta = con.createStatement();
String AutomationUser1 = "select * from Users where username='AutomationUser1'";
ResultSet res1 = sta.executeQuery(AutomationUser1);
if (res1.next()) {
System.out.println("ResultSet is not empty, 1 row returned");
System.out.println("AutomationUser1 test user already exists so deleting the existing and creating it again");
String deleteUser = "delete from Users where UserName='AutomationUser1'";
String deleteUserEmail = "delete from UserAdditionalInfo where Email='AutomationUser1@email.com'";
sta.executeUpdate(deleteUser);
sta.executeUpdate(deleteUserEmail);
driver.findElement(By.xpath("//input[@id='UserName']")).clear();
driver.findElement(By.xpath("//input[@id='UserName']")).sendKeys(cells.get(1).get(1));
driver.findElement(By.xpath("//input[@id='UserEmail']")).sendKeys(cells.get(2).get(1));
} else if (!res1.next()) {
System.out.println("ResultSet is empty, no rows returned");
System.out.println("Test user does not exist so creating test user : AutomationUser1");
driver.findElement(By.xpath("//input[@id='User']")).clear();
driver.findElement(By.xpath("//input[@id='User']")).sendKeys(cells.get(1).get(1));
driver.findElement(By.xpath("//input[@id='UserEmail']")).sendKeys(cells.get(2).get(1));
} else {
Assert.assertTrue(false);
}
}
}
August 1, 2022
July 29, 2022
PageFactory design pattern (enhanced POM) in selenium with cucumber and java
( JasperSoft BI Suite Tutorials - Sadakar Pochampalli )
Hi, In this tutorial, we look at the differences between POM and PageFactory in selenium and
an end to end example implementation of PageFactory design pattern of POM.
What is the usage of Page Object Model (POM) and PageFactory class?
- We can separate the test objects(web elements are the test objects) from the test scripts.
- Advantages:
- Code reusability, maintainability, repositoy of objects, better redability.
Page Object Model (POM)
- An OOPs test design pattern using page class.
- We organize each web page objects/elements in a class.
- Test scripts are maintained in separate class.
- Locators are defined using "By" (By is a selenium class)
- Example:
public By userNameLocator = By.xpath("//*[@id=\"txtUsername\"]");
PageFactory:
- PageFactory is a selenium class; It is an optimized approach to implement the Page Object Model using PageFactory class.
- Locators are defined using "@FindBy" annotation of PageFactory class.
- Example:
@FindBy(xpath = "//*[@id=\"txtUsername\"]")
public WebElement userNameLocator;
@FindBys({
@FindBy(id="xyz"),
@FindBy(id="pqr")
})
- We use initElements method to initialize the elements of the web page.
- Example: Using class
HRMLoginPageFactory hrmLoginPF =
PageFactory.initElements(driver, HRMLoginPageFactory.class);
- Example: Using a Constructor
public HRMLoginPageFactory(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
Now, let's begin with an example:
Scenarios:
Login to the HRM Application
Navigate to Directory page and check for the Search button presence.
Login to the HRM Application
Navigate to Directory page and check for the Search button presence.
Project structure:
Download this example from GitHub or Download this Zip and import in Eclipse
NOTE :
In the downloaded code update this : return searchButtonLocator.isDisplayed(); in DirectoryPageFactory.java file
In the downloaded code update this : return searchButtonLocator.isDisplayed(); in DirectoryPageFactory.java file
Steps:
- Download and install cucumber plug-in in Eclipse from Market Place
- Download and install TestNG plug-in in Eclipse from Market Place
- Create a new Maven project (say : CucumberTestNGSeleniumMavenPageFactoryPattern)
- Add the following dependencies in pom.xml
- cucumber-java 7.1.0
- cucumber-testng 7.1.0
- selenium-java 4.3.0
- testng 7.1.0
- Add the following plug-ins in pom.xml
- maven-surefire-plugin 3.0.0-M7
- maven-compiler-plugin 3.10.1
- Create feature files in
- folder: src/test/resources
- HRMLogin.feature
- Directory.feature
- Write code for cucumber runner
- folder : src/test/java
- package : com.sadakar.testng.runner
- class : RunCucumberTest.java
- Write code for driver, hooks
- folder : src/test/java
- package: com.sadakar.common
- BasePage.java for driver
- Hooks.java for Before and After cucumber hooks
- Write code for page objects in Page Factory classes
In this phase, implement page objects in page factory classes for each of the UI page and refer them wherever required in step definitions. In a long term, if there are any changes in locators, we can just refer to the particular page factory class and update at once.
Using this approach we can reduce a lot of code redundancy.
Using this approach we can reduce a lot of code redundancy.
- folder : src/test/java
- package: com.sadakar.pageobjects
- HRMLoginPageFactory.java for HRMLogin page web elements,
- for instance locating username, password and login button
- DirectoryPageFactory.java for Directory page web element,
- for instance view directory tab link, search button
- Write code for step definitions or say glue code
- HRMLogin.java
- Directory.java
- Run the scenarios from mvn command line
- Navigate to the project folder
- Run the below command for two scenarios.
mvn test -Dcucumber.filter.tags="@LoginValidCredentials or @DirectoryTabIsSearchButtonDisplayed"
Tap on the image for best view: - Run the scenarios from TestNG in eclipse and report analysis
- Right click on the project and then Run as TestNG
- Report will be generated at
- test-output> emailable-report.html
- Tap on the image for best view:
- Run the project using testng.xml
- Right click on the project > Run as testng.xml
- Report is same as above
- Make sure testng.xml is added in pom.xml file as configuration
- Analysis of cucumber report
Install all the required jars in the project by defining the dependencies and or plug-ins.
HRMLogin.feature
Login feature file, in use DataTable approach for username and password.
Directory.feature
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>CucumberTestNGSeleniumMavenPageFactoryPattern</groupId>
<artifactId>CucumberTestNGSeleniumMavenPageFactoryPattern</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>7.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin -->
<dependency>
<groupId>tech.grasshopper</groupId>
<artifactId>extentreports-cucumber7-adapter</artifactId>
<version>1.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.0.8</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<systemPropertyVariables>
<extent.reporter.spark.start>true</extent.reporter.spark.start>
<extent.reporter.spark.out>test-output/SparkReport/Spark.html</extent.reporter.spark.out>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Login feature file, in use DataTable approach for username and password.
@HRMLogin
Feature: Login to HRM Application
I want to use this template for HRM Login page
@LoginValidCredentials
Scenario: LoginValidCredentials
Given User login to HRM application with UserName and Password
| Admin | admin123 |
Take the Login feature scenario as Background so repeated code can be avoided for login.
It's a good practice to implement tests independent so login is taken separately and the directory is taken separately including login.
RunCucumberTest.java
It's a good practice to implement tests independent so login is taken separately and the directory is taken separately including login.
@Directory
Feature: Dashboard page
I want to use this template for my Directory Page
Background:
Given User login to HRM application with UserName and Password
| Admin | admin123 |
@DirectoryTabIsSearchButtonDisplayed
Scenario: DirectoryTabIsSearchButtonDisplayed
Then User is on Directory page
Then Is Search button displayed
> tags syntax has beeen changed over time, with 7.1, cucumber accepts or , and , not
> classpath.features finds the features in the project.
> glue identifies the code the project
> plugin is used to create cucumber report or extent-report (The adapter used is to support 4.3 selenium)
> RunCucumberTest -- always append Test at the end of cucumber runner class so the testng identifies the root for the scripts.
package com.sadakar.testng.runner;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
@CucumberOptions(
tags = "@LoginValidCredentials or @DirectoryTabIsSearchButtonDisplayed",
features = "classpath:features", glue = { "com.sadakar.common", "com.sadakar.stepdefinitions",
"com.sadakar.testng.runner" },
plugin = { "pretty", "json:target/cucumber-reports/cucumber.json",
"html:target/cucumber-reports/cucumberreport.html",
"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"},
monochrome = true)
public class RunCucumberTest extends AbstractTestNGCucumberTests {
}
> I would prefer to keep the initialization of driver in a BasePage class since at a later time, if the execution has to be done through a jar, I can keep the CLI(Command Line Interface)
Hooks.java
package com.sadakar.common;
import org.openqa.selenium.WebDriver;
public class BasePage {
public static WebDriver driver;
}
> Here Before is a cucumber hook, using it set the driver for chrome, access the app url and etc.
> After is also a cucumber hook and after each scenario the driver quits.
HRMLoginPageFactory.java
package com.sadakar.common;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.After;
import io.cucumber.java.Before;
public class Hooks extends BasePage {
@Before //Cucumber Before Hook
public void setupDriver() throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://opensource-demo.orangehrmlive.com/index.php/auth/login");
}
@After // Cucumber After hook
public void quitDriver() throws Exception {
driver.quit();
}
}
> In this class, we store the web elements as objects and perform actions so that we can hide the implementation of actual test scripts.
> Every page factory class require a driver to find the elements and we activate the driver in the class constructor
> Every page factory class require a driver to find the elements and we activate the driver in the class constructor
> Using @FindBy annotation find the element of web page
> loginHRM is the user defined method in which the actual logic is written to login to the application.
This is separated out from the cucumber test script.
DirectoryPageFactory.java
package com.sadakar.pageobjects;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class HRMLoginPageFactory {
final WebDriver driver;
// Constructor, as every page needs a Webdriver to find elements
public HRMLoginPageFactory(WebDriver driver) {
this.driver = driver;
}
// Locators for User Name, Password and for Login button
// UserName
@FindBy(xpath = "//*[@id=\"txtUsername\"]")
public WebElement userNameLocator;
// Password
@FindBy(xpath = "//*[@id=\"txtPassword\"]")
public WebElement passwordLocator;
// Login button
@FindBy(id = "btnLogin")
public WebElement loginButtonLocator;
// Method that performs Login action using the web elements
public void loginHRM(String uName, String pwd) {
userNameLocator.sendKeys(uName);
passwordLocator.sendKeys(pwd);
loginButtonLocator.click();
}
}
> Code walkthrough is same as above factory class.
HRMLogin.java
package com.sadakar.pageobjects;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class DirectoryPageFactory {
final WebDriver driver;
// Constructor, as every page needs a Webdriver to find elements
public DirectoryPageFactory(WebDriver driver) {
this.driver = driver;
}
// Locators for directory tab,search button
// Directory tab locator
@FindBy(xpath = "//*[@id=\"menu_directory_viewDirectory\"]")
public WebElement viewDirectoryLinkLocator;
// Search button locator
@FindBy(xpath = "//*[@id=\"searchBtn\"]")
public WebElement searchButtonLocator;
// Method that performs click on Directory tab
public void viewDirectoryTabNavigation() {
viewDirectoryLinkLocator.click();
}
// Method that checks the search button presence
public boolean verifySearchButtonPresense() {
return searchButtonLocator.isDisplayed();
}
}
> Cucumber step definition for login page.
> In the feature file, the username and password is taken as data driven test.
> Define page factory class object hrmLoginPF and initiate the elements using initElements method
Directory.java
package com.sadakar.stepdefinitions;
import java.time.Duration;
import java.util.List;
import org.openqa.selenium.support.PageFactory;
import com.sadakar.common.BasePage;
import com.sadakar.pageobjects.HRMLoginPageFactory;
import io.cucumber.java.en.Given;
public class HRMLogin extends BasePage {
HRMLoginPageFactory hrmLoginPF = PageFactory.initElements(driver, HRMLoginPageFactory.class);
@Given("User login to HRM application with UserName and Password")
public void loginToHRMApp(io.cucumber.datatable.DataTable dataTable) {
List<List<String>> cells = dataTable.cells();
hrmLoginPF.loginHRM(cells.get(0).get(0), cells.get(0).get(1));
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
}
> Code explanation is similar as above class
package com.sadakar.stepdefinitions;
import java.time.Duration;
import org.openqa.selenium.support.PageFactory;
import org.testng.Assert;
import com.sadakar.common.BasePage;
import com.sadakar.pageobjects.DirectoryPageFactory;
import io.cucumber.java.en.Then;
public class Directory extends BasePage{
DirectoryPageFactory directoryPF = PageFactory.initElements(driver, DirectoryPageFactory.class);
@Then("User is on Directory page")
public void directoryPage() {
// Navigating to Directory Page/tab
directoryPF.viewDirectoryTabNavigation();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
@Then("Is Search button displayed")
public void isSearchButtonDisplayed() {
// Verifying Search button is displayed or not
boolean isSearhButtonDisplayedTrue = directoryPF.verifySearchButtonPresense();
Assert.assertTrue(isSearhButtonDisplayedTrue);
}
}
This article also has extent-reports included that is not discussed in steps.
July 29, 2022
July 18, 2022
Page Object Model (POM) in selenium with cucumber testng, maven | end to end example
( JasperSoft BI Suite Tutorials - Sadakar Pochampalli )
POM - Page Object Model
- It is a design pattern / frame work in selenium.
- Using this pattern, we can create object repository for web elements in the UI.
- We create a POM class file(Example: HRMLoginPOM.java) for each web page such that it consists of all web elements present in the page.
- Testing scripts(Example: HRMLogin.java) uses the the elements from POM class file
Project Structure:
Source Code : Download from GitHub or Click this link
Or Watch this No Voice Video Tutotial for the same example
Steps:
- Download and install cucumber plug-in in Eclipse from Market Place
- Download and install TestNG plug-in in Eclipse from Market Place
- Create a new Maven project (say : CucucumberTestNGSeleniumMavenPageObjectModel)
- Add the following dependencies in pom.xml
- cucumber-java 7.1.0
- cucumber-testng 7.1.0
- selenium-java 4.3.0
- testng 7.1.0
- Add the following plug-ins in pom.xml
- maven-surefire-plugin 3.0.0-M7
- maven-compiler-plugin 3.10.1
- Create feature files in
- folder: src/test/resources
- HRMLogin.feature
- Directory.feature
- Write code for cucumber runner
- folder : src/test/java
- package : com.sadakar.testng.runner
- class : RunCucumberTest.java
- Write code for driver, hooks
- folder : src/test/java
- package: com.sadakar.common
- BasePage.java for driver
- Hooks.java for Before and After cucumber hooks
- Write code for page objects
In this phase, implement page objects in separate classes for each of the UI page and refer them wherever required in steps definitions. In a long term, if there are any changes in locators, we can just refer to the particular POM class and update at once.
Using this approach we can also reduce the code redundancy.
Using this approach we can also reduce the code redundancy.
- folder : src/test/java
- package: com.sadakar.pageobjects
- HRMLoginPOM.java for HRMLogin page web elements,
- for instance locating username, password and login button
- DirectoryPOM.java for Directory page web element,
- for instance view directory tab link, search button
- Write code for step definitions or say glue code
- HRMLogin.java
- Directory.java
- Run the scenarios from mvn command line
- Navigate to the project folder
- Run the below command for two scenarios.
mvn test -Dcucumber.filter.tags="@LoginValidCredentials or @DirectoryTabIsSearchButtonDisplayed"
Tap on the image for best view: - Run the scenarios from TestNG in eclipse and report analysis
- Right click on the project and then Run as TestNG
- Report will be generated at
- test-output> emailable-report.html
- Tap on the image for best view:
- Run the project using testng.xml
- Right click on the project > Run as testng.xml
- Report is same as above
- Make sure testng.xml is added in pom.xml file as configuration
- Analysis of cucumber report
- Cucumber report is available at
- target > cucumber-reports > cucumberreport.html
- Tap on the image for better view.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>CucucumberTestNGSeleniumMavenPageObjectModel</groupId>
<artifactId>CucucumberTestNGSeleniumMavenPageObjectModel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>7.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin -->
<dependency>
<groupId>tech.grasshopper</groupId>
<artifactId>extentreports-cucumber7-adapter</artifactId>
<version>1.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.0.8</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
<systemPropertyVariables>
<extent.reporter.spark.start>true</extent.reporter.spark.start>
<extent.reporter.spark.out>test-output/SparkReport/Spark.html</extent.reporter.spark.out>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
HRMLogin.feature
@HRMLogin
Feature: Login to HRM Application
I want to use this template for HRM Login page
@LoginValidCredentials
Scenario: LoginValidCredentials
Given User login to HRM application with UserName and Password
| Admin | admin123 |
Directory.feature
@Directory
Feature: Dashboard page
I want to use this template for my Directory Page
Background:
Given User login to HRM application with UserName and Password
| Admin | admin123 |
@DirectoryTabIsSearchButtonDisplayed
Scenario: DirectoryTabIsSearchButtonDisplayed
Then User is on Directory page
Then Is Search button displayed
RunCucumberTest.java
package com.sadakar.testng.runner;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
@CucumberOptions(
tags = "@LoginValidCredentials or @DirectoryTabIsSearchButtonDisplayed",
features = "classpath:features", glue = { "com.sadakar.common", "com.sadakar.stepdefinitions",
"com.sadakar.testng.runner" },
plugin = { "pretty", "json:target/cucumber-reports/cucumber.json",
"html:target/cucumber-reports/cucumberreport.html",
"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"},
monochrome = true)
public class RunCucumberTest extends AbstractTestNGCucumberTests {
}
BasePage.java
package com.sadakar.common;
import org.openqa.selenium.WebDriver;
public class BasePage {
public static WebDriver driver;
}
Hooks.java
package com.sadakar.common;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.After;
import io.cucumber.java.Before;
public class Hooks extends BasePage {
@Before //Cucumber Before Hook
public static void setupDriver() throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://opensource-demo.orangehrmlive.com/index.php/auth/login");
}
@After // Cucumber After hook
public static void quitDriver() throws Exception {
driver.quit();
}
}
HRMLoginPOM.java
DirecotryPOM.javapackage com.sadakar.pageobjects;
import org.openqa.selenium.By;
public class HRMLoginPOM {
// Locators for username, password, loginButton
public By userNameLocator = By.xpath("//*[@id=\"txtUsername\"]");
public By passwordLocator = By.xpath("//*[@id=\"txtPassword\"]");
public By loginButtonLocator = By.id("btnLogin");
}
package com.sadakar.pageobjects;
import org.openqa.selenium.By;
public class DirectoryPOM {
// locators for view Directory Page/Tab, Search button
public By viewDirectoryLinkLocator = By.xpath("//*[@id=\"menu_directory_viewDirectory\"]");
public By searchButtonLocator = By.xpath("//*[@id=\"searchBtn\"]");
}
HRMLogIn.java
Directory.javapackage com.sadakar.stepdefinitions;
import java.time.Duration;
import java.util.List;
import com.sadakar.common.BasePage;
import com.sadakar.pageobjects.HRMLoginPOM;
import io.cucumber.java.en.Given;
public class HRMLogin extends BasePage {
HRMLoginPOM hrm = new HRMLoginPOM();
@Given("User login to HRM application with UserName and Password")
public void loginToHRMApp(io.cucumber.datatable.DataTable dataTable) {
List<List<String>> cells = dataTable.cells();
driver.findElement(hrm.userNameLocator).sendKeys(cells.get(0).get(0));
driver.findElement(hrm.passwordLocator).sendKeys(cells.get(0).get(1));
driver.findElement(hrm.loginButtonLocator).submit();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
}
package com.sadakar.stepdefinitions;
import java.time.Duration;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import com.sadakar.common.BasePage;
import com.sadakar.pageobjects.DirectoryPOM;
import io.cucumber.java.en.Then;
public class Directory extends BasePage{
DirectoryPOM dir = new DirectoryPOM();
@Then("User is on Directory page")
public void directoryPage() {
// Navigating to Directory Page/tab
driver.findElement(dir.viewDirectoryLinkLocator).click();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
@Then("Is Search button displayed")
public void isSearchButtonDisplayed() {
// Verifying Search button is displayed or not
WebElement searchButtonEle = driver.findElement(dir.searchButtonLocator);
Assert.assertTrue(searchButtonEle.isDisplayed());
}
}
Cheers!, I hope this helped you implement Page Object Model using cucumber, selenium and testng.
This article also has extent-reports included that is not discussed in steps.
July 18, 2022
Pages
About
Planet Jaspersoft aggregates blog posts from our community. If you would like your blog to be included in the Planet, please follow this help guide. Or just click this link to go straight to your Planet Feeds.
Feed Sources
- JasperSoft BI Suite Tutorials - Sadakar Pochampalli (273) Apply JasperSoft BI Suite Tutorials - Sadakar Pochampalli filter
- Technology Blog (50) Apply Technology Blog filter
- Jaspersoft Tech Talks (41) Apply Jaspersoft Tech Talks filter
- Jaspersoft Tutorials (30) Apply Jaspersoft Tutorials filter
- The Open Book on BI (26) Apply The Open Book on BI filter
- Rajesh Sirsikar (22) Apply Rajesh Sirsikar filter
- Bekwam Data as a Service (21) Apply Bekwam Data as a Service filter
- AgileTech - Ankur Gupta (19) Apply AgileTech - Ankur Gupta filter
- Ankur Gupta - Youtube (17) Apply Ankur Gupta - Youtube filter
- Digital Gene (15) Apply Digital Gene filter
- Tech Poet (13) Apply Tech Poet filter
- iTransparent - Jaspersoft Blog (9) Apply iTransparent - Jaspersoft Blog filter
- Paco Saucedo's blog » JasperReports (6) Apply Paco Saucedo's blog » JasperReports filter
- David Hoppmann's JasperServer Posts (2) Apply David Hoppmann's JasperServer Posts filter
- Jasper Related Posts from Wedjaa (1) Apply Jasper Related Posts from Wedjaa filter