Background: We had a very big step definition and it was getting difficult to manage it. So, we have decided to split step definition into multiple small definitions using this new automation base.
Stack: Selenium, Java, Cucumber,Junit, Picocontainer.
To achieve the above, we have looked for lot of suggestions on various websites and stackoverflow discussion, There are many suggestions like using Dependency Injection (Picocontainer), use Constructor Injection, spring etc.
After going through all those suggestions we used Pico Container dependency injection solution. It helped in:
- To divide 1 big stepdef into multiple.
- Sharing data between step defs as well.
Now, we are facing below problems:
When we use are running Smoke test using ScenarioOutline and example. Feature File1 example. then we get error like: org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
Unable to Run multiple feature file in feature folder using 1 TestRunner Class.
Solution tried: When we do not use static Webdriver in DriverFactoryManager then, it works perfectly, I can run Feature File1 with ScenarioOutline also, I can run multiple feature file in sequence using 1 test runner.
However, If a feature file has more than 1 test scenario like FeatureFile2 , then it does not run 2nd scenario.and give error. In DriverFactory when we make Webdriver static then it keep the session and helps to execute all scenarios listed in 1 feature file.
Could you please help to achieve 3 things :
- MY Feature file with multiple scenario for eCommerce website should be able to execute all cases listed with 1 browser session.
- All the feature file listed in Feature file can be executed in parallel or sequential using Test Runner.
src/main/java
|->baseFramework
|-->pagefactory
| |----- LoginPage.class
| |----- HomePage.class
| |----- ProductPage.class
| |----- PaymentPage.class
|-->picoHelper
| |-----PicoHelperPage.class
| |-----SharedData.class
|-->helpers
| |-->wait
| |-----waitHelper.class
| |-->util
| |-----DriverFactoryManager.class
| |-----PageFactoryManager.class
src/test/testBase
|-->stepDefinition
| |-----LoginStepDef.class
| |-----HomePageStepDef.class
| |-----ProductStepDef.class
| |-----PaymentStepDef.class
|-->Runner
| |-----TestRunner
src/test/features
|-->SanityTest
| |-----Login.feature
| |-----Product.feature
Feature file1:
#Author : Nikhil Kumar
#Feature: Smoke login test for all different version of test and staging environment
@Smoke
Feature: To Test the functionality of login and logout of various environment and tenant
Scenario Outline: Smoke login test for all different version of test and staging environment
Given Browser has been launched
When User navigate to loginpage of "<Environment>" environment
And User enters <username> and <password>
And Clicks on SignIn button
Then User should be able to see homepage
And User should be able to logout
Examples:
| Environment | username | password |
| Test | xxx.x@com | qwert |
Feature file2:
#Author : Nikhil Kumar
#Feature: Smoke login test for all different version of test and staging environment
@Smoke
Feature: A test
Scenario: Successful Login to with Valid Credentials
Given Browser has been launched
When User navigate to loginpage of "Test" environment
And User enters valid credentials for Tenant "Test1"
And Clicks on SignIn button
Then User should be able to see homepage
Scenario:check logout link
Given User is logged in
When User clicks on user avatar
Then User should see logout link and logout sucessfully
DriverFactoryManager
public class DriverFactoryManager {
static WebDriver driver = null;
public DriverFactoryManager() {
//Blank
}
// To launch driver
public WebDriver getDriver() {
if (driver == null) {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
}
return driver;
}
PageObjectManager
private WebDriver driver;
private LoginPage login;
private AdvanceSearchPage objAdvSrh;
private ProductManagerPage objPM;
private HomePage home;
public PageObjectManager(WebDriver driver) {
this.driver = driver;
}
public LoginPage getLoginPage() {
if (login == null) {
login = new LoginPage(driver);
}
return login;
// return (lp == null) ? lp = new LoginPage(driver) : lp;
}
public HomePage getHomePage() {
return (home == null) ? home = new HomePage(driver) : home;
}
public ProductManagerPage getProductManagerPage() {
return (objPM == null) ? objPM = new ProductManagerPage(driver) : objPM;
}
and so on for all pages.....
picoHelperPage looks like:
public class PicoHelperPage {
DriverFactoryManager driverFactoryManager;
PageObjectManager pageObjectManager;
public PicoHelperPage() {
driverFactoryManager = new DriverFactoryManager();
pageObjectManager = new PageObjectManager(driverFactoryManager.getDriver());
log.info("PicContainer : Starting Execution from Initializing constructor for PicContainer class");
}
public DriverFactoryManager getDriverFactoryManager() {
return driverFactoryManager;
}
public PageObjectManager getPageObjectManager() {
return pageObjectManager;
}
}
Step definition: LoginStepDef
public class LoginStepDef {
LoginPage login;
PicoHelperPage picoHelper;
private Logger log = LoggerHelper.getLogger(LoginStepDef.class);
public LoginStepDef(PicoHelperPage picHelper) throws IOException {
picoHelper = picHelper;
login = picoHelper.getPageObjectManager().getLoginPage();
}
@When("User navigate to loginpage of \"(.*)\" environment of Comestri$")
public void userNavigateToHomepageOfComestri(String env) {
login.navigateTo_HomePage(env);
}
/**
* COMESTRI: ADMIN PAGE CREDENTIALS
*/
@And("^User enters valid credentials for Comestri Tenant \"(.*)\"$")
public void userEntersCredentials(String version) {
login.entersCredentials(version);
}
@When("^User enters (.*) and (.*)$")
public void userEntersUsernameAndPassword(String Username, String Password) {
System.out.println("entering credentials");
login.entersUsername(Username);
login.entersPassword(Password);
}
@And("Clicks on SignIn button")
public void clicksOnSignInButton() {
login.clickSigin();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String errorMsg = "Invalid Email or password.";
if (login.getPageSource().contains(errorMsg)) {
Assert.fail("User with Invalid Credential is trying to Login. Test case failed...");
} else {
System.out.println("valid user is trying to login....");
}
}
Homepage StepDefs
package CucumberTest.stepDefinitions;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import cucumberBase.driverFactory.managers.PageObjectManager;
import cucumberBase.helpers.logger.LoggerHelper;
import cucumberBase.pageFactory.HomePage;
import cucumberBase.picoHelper.TestContext;
import org.apache.log4j.Logger;
public class HomeStepDef {
PicoHelperpage picHelper;
WebDriver driver;
HomePage home;
public HomeStepDef(PicoHelperpage picHelper;) {
picoHelper= picHelper;
home = picoHelper.getPageObjectManager().getHomePage();
}
@When("User clicks on user avatar")
public void userClicksOnUserAvatar() {
home.clickSignOutMenu();
log.info("Avatar Icon is clicked...");
}
@Then("User should see logout link and logout sucessfully")
public void userShouldSeeLogoutLink() {
log.info("Signout button must be visible now");
home.clickLogOut();
log.info("User Logged out Successfully.......");
// THis below line will close driver...
home.driverClose();
}
@And("User should be able to logout")
public void Logout() {
home.clickSignOutMenu();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
home.clickLogOut();
log.info("Successfully Logout of system....");
home.driverClose();
}
@When("User click at link on LHS menu")
public void userClickAtLinkOnLHSMenu() {
System.out.println("LHS all links are clickable...");
}
@Then("User should be able to see proper pages")
public void userShouldBeAbleToSeeProperPages() {
System.out.println("Expected pages are visible/............");
}
}
LoginPage
package cucumberBase.pageFactory;
import cucumberBase.helpers.dropDown.DropDownHelper;
import cucumberBase.helpers.javaScript.JavaScriptHelper;
import cucumberBase.helpers.logger.LoggerHelper;
import cucumberBase.helpers.wait.WaitHelper;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class LoginPage {
WebDriver driver;
WaitHelper waitHelper;
JavaScriptHelper jsHelper;
DropDownHelper selectHelper;
private final Logger log = LoggerHelper.getLogger(LoginPage.class);
/**
* THese are all locator for Login section
*/
@FindBy(id = "user_email")
@CacheLookup
WebElement txt_userEmail;
@FindBy(id = "user_password")
@CacheLookup
WebElement txt_password;
@FindBy(xpath = "..xpath...")
@CacheLookup
WebElement btn_SignIn;
/**
* This is constuctor of class
*/
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
/**
* These are Action methods for Login page elements
*/
public void entersUsername(String strUserName) {
txt_userEmail.sendKeys(strUserName);
}
public void entersPassword(String strPassword) {
txt_password.sendKeys(strPassword);
}
/**
* These are Action methods for SignIn page elements
*/
public void clickSigin() {
btn_SignIn.click();
}
public void entersCredentials(String version) {
switch (version) {
case ("Test1"):
String strUserName = "username1";
String strPassword = "password1");
this.entersUsername(strUserName);
this.entersPassword(strPassword);
break;
case ("Test2"):
String strUserName1 = "Username2";
String strPassword1 = "password2";
this.entersUsername(strUserName1);
this.entersPassword(strPassword1);
break;
}
log.info("Method Action: enterCredentials has been completed....");
}
//
public void navigateTo_HomePage(String env) {
if (env.equals("Test")) {
driver.get("https://www.gmail.com");
driver.manage().window().maximize();
log.info(" Test: Navigated to admin page...."); // 22/04 : added by nikhil
} else if (env.equals("Staging")) {
driver.get("https://www.amazon.com);
driver.manage().window().maximize();
log.info("STAGING ENV: Navigated to admin page...."); // 22/04 : added by nikhil
}
}
// This method used for assertions and get Page Tile
public String getPageTitle() {
return driver.getTitle();
}
// This method used for validation pageSource content
public String getPageSource() {
return driver.getPageSource();
}
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
}
HomePage
package cucumberBase.pageFactory;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class HomePage {
WebDriver driver;
/**
* These are Element Locators
*/
@FindBy(xpath = "//div[@class='avatar-label']")
private WebElement btn_signOutMenu;
@FindBy(xpath = "//a[contains(.,'Sign Out')]")
private WebElement lnk_signoutLink;
/**
* This is a Constructor, used to pass driver of stepdef to maintain same session
*
* @param driver is refering to driver declared in main step def
* initElements is used to initialize all element of this page,whenever obj of this class gets created.
*/
public HomePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
/**
* These are Action methods for Login page elements
*/
public void clickSignOutMenu() {
btn_signOutMenu.click();
}
public void clickLogOut() {
Actions action = new Actions(driver);
action.moveToElement(lnk_signoutLink).click();
action.perform();
}
public void driverClose() {
System.out.println("homepage");
driver.close();
driver.quit();
}
}
Pom File
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>projectname</artifactId>
<version>5.1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.version>4.3.0</cucumber.version>
<selenium.version>3.141.5</selenium.version>
<java.version>1.8</java.version>
<maven.compiler.version>3.8.1</maven.compiler.version>
<maven.surefire.version>2.22.2</maven.surefire.version>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>net.masterthought</groupId>
<artifactId>cucumber-reporting</artifactId>
<version>4.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/tech.grasshopper/extentreports-cucumber6-adapter -->
<dependency>
<groupId>tech.grasshopper</groupId>
<artifactId>extentreports-cucumber6-adapter</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.0.9</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.12.2</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jexcelapi</groupId>
<artifactId>jxl</artifactId>
<version>2.6.12</version>
</dependency>
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.jtwig</groupId>
<artifactId>jtwig-core</artifactId>
<version>5.87.0.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<defaultGoal>compile</defaultGoal>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<encoding>UTF-8</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.version}</version>
<configuration>
<includes>
<include>**/*Runner.*</include>
</includes>
<parallel>methods</parallel>
<threadCount>4</threadCount>
<perCoreThreadCount>true</perCoreThreadCount>
</configuration>
</plugin>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Could someone please suggest a way to resolve my issues