Switch Window Commands in Selenium WebDriver

HOME

One of the major testing workflows involves switching between multiple windows. Selenium WebDriver has specific switch commands to serve this purpose. Selenium WebDriver assigns an alphanumeric id to each window as soon as the WebDriver object is instantiated. This unique alphanumeric id is called a window handle. Selenium uses this unique id to switch control among several windows. In simple terms, each unique window has a unique ID, so that Selenium can differentiate when it is switching controls from one window to the other.

1) GetWindowHandle

To get the window handle of the current window. It returns a string of alphanumeric window handles.

String  parentHandle= driver.getWindowHandle();

2) GetWindowHandles

To get the window handle of all the windows. It returns a set of window handle.

Set  handle= driver.getWindowHandles();

3) SwitchTo Window

WebDriver supports moving between named windows using the “switchTo” method.

driver.switchTo().window("windowName");

Let us explain window switch with an example:-

1) Launch new Browser and open https://demoqa.com/browser-windows
2) Check the count of windows which is 1
3) Locate “New Window” button using Id – “windowButton” and click to open a new window
4) Get the count of both windows which is now 2.
5) Get the parent window handle and print it to console
6) Get the window handles of both the open windows and print them
7) Switch to the new window (child window)
8) Get the text of Child Window and print it
9) Close the new window (child window)

The program for the above scenario is shown below:

package com.example.definitions;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class WindowSwitchDemo {

    public static void main(String[] args) {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        WebDriver driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

        // Pass application url
        driver.get("https://demoqa.com/browser-windows");

        //Count of window - 1
        Set<String> allWindowHandles = driver.getWindowHandles();
        System.out.println("Count of Window :" + allWindowHandles.size());

        //Open a child window
        driver.findElement(By.id("windowButton")).click();

        //Count of windows , changed from 1 to 2
        Set<String> newAllWindowHandles = driver.getWindowHandles();
        System.out.println("New Count of Window :" + newAllWindowHandles.size());

        // Get the detail of the parent window
        String ParentHandle = driver.getWindowHandle();
        System.out.println("Parent Window :" + ParentHandle);

        //Get details of parent and child windows
        Iterator<String> iterator = newAllWindowHandles.iterator();
        String mainWindow = iterator.next();
        String childWindow = iterator.next();
        System.out.println("Parent Window :" + mainWindow);
        System.out.println("Child Window :" + childWindow);

        //Switch control to child window
        driver.switchTo().window(childWindow);

        //Verify the text present on child window
        WebElement text = driver.findElement(By.id("sampleHeading"));
        System.out.println("Child_Title :" + text.getText());

        // Close Child window
        driver.close();

        // Switch back to parent window
        driver.switchTo().window(ParentHandle);
        System.out.println("Parent Title :" + driver.getTitle());

        // Close Parent window
        driver.quit();
    }

}

What is the difference between driver.close() and driver.quit()?

When we are working on multiple windows and a selective window needs to be closed, then transfer the control to that window and use driver.close() to close the selective window. This will not stop the execution of the rest of the program. But, in case it is needed to close all the open windows, then use driver.quit() which will close all the windows opened in a particular session. It basically stops the driver instance, and any further actions to WebDriver may result in an exception.  It is generally the last statement of any code.

Congratulations. We have learnt about window switching in Selenium. I hope you find this tutorial helpful. Happy Learning!!

DataTables in Cucumber

Last Updated On

HOME

Cucumber Data Tables can be used to add multiple parameters in Step Definition in a tabular form rather than putting all the parameters in the Gherkin statement. This is much easier to read and multiple rows of data can be passed in the same step. Data tables from Gherkin can be accessed by using the DataTable object as the last parameter in a Step Definition. This conversion can be done either by Cucumber or manually.

Table Of Contents

  1. Prerequisite
  2. Project Structure
    1. Table into List of a List of Strings
    2. Table into List of Maps
    3. Table into Single Map
    4. Table into map that uses a list as its value
  3. Cucumber Data Tables Example in Java
    1. Data Table without Header Example
    2. Data Table with Header and Single Row Example
    3. Data Table with Header and Multiple Rows Example

Prerequisite

  1. Cucumber – 7.15.0
  2. Java – 17
  3. Selenium – 4.16.1
  4. JUnit – 4.13.2 ( You can use TestNG also)
  5. Cucumber JUnit – 7.15.0 (If using TestNG, then replace this with Cucumber TestNG)

Project Structure

Depending on the table shape, we can use one of the following collections:

List<List<String>> table
List<Map<String, String>> table
Map<String, String> table
Map<String, List<String>> table
Map<String, Map<String, String>> table

Let’s write a simple data table and see how we use it.

1. Table into List of a List of Strings

| firstName | lastName | age |
| Thomas    | Brown | 30 |
| Perry     | Wilson | 26 |
| Ashley    | William | 27 |

java type: List<List<String>>

The natural representation of list of a list of strings is shown below.

[ 
  [ "firstName", "lastName", "age" ],
  [ "Thomas", "Brown", "30" ], 
  [ "Perry", "Wilson", "26" ], 
  [ "Ashley", "William", "27" ] 
]

2. Table into List of Maps

java type: List<Map<String, String>>
The natural representation of list of maps is shown below.

[
  { "firstName": "Thomas", "lastName": "Brown",  "age": "30" }, 
  { "firstName": "Perry",  "lastName": "Wilson", "age": "26" }, 
  { "firstName": "Ashley", "lastName": "William", "age": "27" } 
]

3. Table into Single Map

Table where first colum is key as shown below

| IN  | India          |
| IRE | Ireland        |
java type: Map<String, String>

TO convert the table into a single map

{
  "IN": "India",
  "IRE": "Ireland"
}

4. Table into map that uses a list as its value

 A table with multiple column values per key.
 
 | IN  | India          | 29  |
 | IRE | Ireland        | 8   |

java type: Map<String, List<String>>

{
  "IN":  ["India","29"],
  "IRE": ["Ireland","8"]
}

Now, let us see how we can use DataTable in Cucumber

Cucumber Data Tables Example in Java

Data Table without Header Example

Below is an example of how to implement Data Tables without a Header. For example, we want to test the Login Page of an application. We can either mention all the arguments inside the Gherkin statement or use a table to list all the arguments, as we used below:

Feature: Login to HRM Application 
 
  @ValidCredentials
  Scenario: Login with valid credentials - Data Table without Header

    Given User is on HRMLogin page
    When User enters valid credentials
      | Admin | admin123 |
    Then User should be able to login successfully and new page open

Below is the Step Definition of the above scenario.

import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;

public class DataTableDefinitions {

    WebDriver driver;

 @Before
    public void setup() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

    @Given("User is on HRMLogin page")
    public void userOnHomePage() {

        driver.get("https://opensource-demo.orangehrmlive.com/");
    }

     @When("User enters valid credentials")
    public void entersValidCredential(DataTable dataTable) throws InterruptedException{

        System.out.println("Credentials Entered");

        List<List<String>> signUpForm = dataTable.asLists(String.class);
        String userName = signUpForm.get(0).get(0);
        String passWord = signUpForm.get(0).get(1);
        driver.findElement(By.name("username")).sendKeys(userName);
        driver.findElement(By.name("password")).sendKeys(passWord);
        driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();
    }

    @Then("User should be able to login successfully and new page open")
    public void successfulLogin() throws InterruptedException {

        String newPageText = driver.findElement(By.xpath("//*[@class='oxd-topbar-header-breadcrumb']/h6")).getText();
        System.out.println("newPageText :" + newPageText);
        assertThat(newPageText, containsString("Dashboard"));
    }

    @After
    public void teardown(){
        driver.quit();
    }
}


To run the Feature file, we need a Cucumber TestRunner.

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(monochrome = true, plugin = "pretty", features = "src/test/resources/Features/DataTable.feature",
        glue = "definitions", tags="@ValidCredentials")

public class CucumberRunnerTest {
}

The output of the above program is

In the above example, we don’t have a header. We have just got the List object. We get the values of DataTable starting from 0 index.

Cucumber converts the above table into a list of lists. It treats each row as a list of the column values. We use the asLists method — supplying a String.class argument — to convert the DataTable argument to a List<List<String>>This Clasargument informs the asLists method of what data type we expect each element to be.

Data Table with Header and Single Row Example

Below is a cucumber data tables example with the header.

Adding a header to your table makes it easier to read and maintain.

  @InValidCredential
  Scenario: Login with invalid credential - Header with Single Row

    Given User is on HRMLogin page
    Then User enters invalid credentials and Login will be unsuccessful with error message
      | Username  | Password   | ErrorMessage        |
      | Admin1    | admin123!$ | Invalid credentials |

Below is the Step Definition of the above scenario.

package org.example.definitions;

import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;
import java.util.List;
import java.util.Map;

public class DataTableDefinitions {

    WebDriver driver;

    @Before
    public void setup() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

    @Given("User is on HRMLogin page")
    public void userOnHomePage() {

        driver.get("https://opensource-demo.orangehrmlive.com/");
    }

    @Then("User enters invalid credentials and Login will be unsuccessful with error message")
    public void entersInvalidCredential(DataTable userTable) throws InterruptedException {

        System.out.println("Enter Credentials");
        List<Map<String, String>> user = userTable.asMaps(String.class, String.class);

        String userName = user.get(0).get("Username");
        System.out.println("Username :" + userName);
        driver.findElement(By.name("username")).sendKeys(userName);

        String passWord = user.get(0).get("Password");
        System.out.println("Password :" + passWord);
        driver.findElement(By.name("password")).sendKeys(passWord);

        driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();

        String errorMessage = user.get(0).get("ErrorMessage");
        String actualErrorMessage = driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();
        System.out.println("Actual Error Message :" + actualErrorMessage);
        Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));

    }

    @After
    public void teardown(){
        driver.quit();
    }

}

The output of the above program is

In the above example, we have only 1 row with the header, so have used get(0) to retrieve the first row of DataTable. After that, I used get(“HeaderName”) to get the value of the row of DataTable.

Data Table with Header and Multiple Rows Example

Below is a cucumber data table example with multiple rows of data with the header. This is helpful when we want to test multiple combinations of data in a step.

  @Multiple_InValidCredentials
  Scenario: Login with invalid credentials - Data Table with Header and Multiple Rows

    Given User is on HRMLogin page
    Then User enters invalid credentials and Login will be unsuccessful with custom error messages
      | Username    | Password  | ErrorMessage         |
      | Admin1      | admin123! | Invalid credentials  |
      | Admina      | admin123a | Invalid credentials  |
   

Below is the Step Definition of the above scenario

import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;

public class DataTableDefinitions {

    WebDriver driver;

     @Before
    public void setup() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));

    }

    @Given("User is on HRMLogin page")
    public void userOnHomePage() {

        driver.get("https://opensource-demo.orangehrmlive.com/");
    }

     @Then("User enters invalid credentials and Login will be unsuccessful with custom error messages")
    public void entersInvalidCredentials(DataTable userTable) throws InterruptedException {

        System.out.println("Enter Credentials");

        List<Map<String, String>> user = userTable.asMaps(String.class, String.class);
        for (Map<String, String> form : user) {

            String userName = form.get("Username");
            System.out.println("Username :" + userName);
            driver.findElement(By.name("username")).sendKeys(userName);

            String passWord = form.get("Password");
            System.out.println("Password :" + passWord);
            driver.findElement(By.name("password")).sendKeys(passWord);

            driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();

            String errorMessage = form.get("ErrorMessage");
            String actualErrorMessage = driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();
            System.out.println("Actual Error Message :" + actualErrorMessage);

            Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));

        }
    }

    @After
    public void teardown(){
        driver.quit();
    }

}

The output of the above program is

Cucumber creates a list containing each row, but instead maps the column heading to each column value. Cucumber repeats this process for each subsequent row. We use the asMaps method — supplying two String.class arguments — to convert the DataTable argument to a List<Map<String, String>>.

The first argument denotes the data type of the key (header). The second indicates the data type of each column value. Thus, we supply two String.class arguments because our headers (key) and title and author (values) are all Strings.

Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!

ArrayList in Java

HOME

  1. What is the difference between Array and ArrayList?
  2. How to create an ArrayList?
  3. How to add elements to an ArrayList?
  4. How to remove elements from ArrayList?
  5. ArrayList SizeMethod
  6. Method to iterate through ArrayList

import java.util.ArrayList; // import the ArrayList class
ArrayListCompanies = new ArrayList(); // Create an ArrayList object


1) To add the element at the end of the List. 

Companies.add("Samsung");

2) To add the element at the specified location in ArrayList, we can specify the index in the add method like this.

Companies.add(2,"Microsoft");

4) How to remove elements from ArrayList?


1) To remove the element with name. 

Companies.remove("MI");

2) To remove the element at the specified location in ArrayList, we can specify the index in the remove method. 

Companies.remove(1);

5) ArrayList SizeMethod

To find out how many elements an ArrayList have, use the size() method. 

Companies.size();

Let me show how to add and remove elements from an ArrayList with the help of an example.

package com.example.definitions;

import java.util.ArrayList;
import java.util.function.Predicate;

public class ArrayList_IteratorExample {

    public static void main(String[] args) {

        //Create ArrayList of String
        ArrayList<String> Companies = new ArrayList();

        // Check if an ArrayList is empty
        System.out.println("Is Company List empty :"+Companies.isEmpty());

        // Adding new elements to the ArrayList
        Companies.add("Samsung");
        Companies.add("Apple");
        Companies.add("Motorola");
        Companies.add("Google");
        Companies.add("Sony");
        Companies.add("Blackberry");
        System.out.println("Company List is :"+Companies);

        // Adding an element at a particular index in an ArrayList
        Companies.add(2,"Microsoft");
        System.out.println("Updated Company List is:"+Companies);

        // Find the size of an ArrayList
        System.out.println("Size of Company List: "+Companies.size());

        // Retrieve the element at a given index
        System.out.println("First Company in list: "+Companies.get(0));

        // Retrieve the last element from ArrayList
        String LastCompany = Companies.get(Companies.size()-1);
        System.out.println("Last Company in list: "+LastCompany);

        // Remove the element
        Companies.remove("MI");

        // Remove the element at index '1'
        Companies.remove(1);
        System.out.println("Updated Company List after removal is:"+Companies);

        // Remove first occurrence of the given element from the ArrayList
        // (The remove() method returns false if the element does not exist in the ArrayList)
        boolean isRemoved = Companies.remove("Lenovo");
        System.out.println("Lenovo exists in Company List :"+isRemoved);

        // Remove all the elements that satisfy the given predicate
        Predicate<String> newCompanies = company -> company.startsWith("B");
        Companies.removeIf(newCompanies);

        System.out.println("After Removing all elements that start with \"B\": " + Companies);
    }
}

6) Method to iterate through ArrayList

There are various methods to iterate through ArrayList. We will discuss few of the methods.
1) Iterator interface
2) For -each loop
3) For loop
4) While loop

package com.example.definitions;

import java.util.ArrayList;

public class ArrayList_IteratorExample {

    public static void main(String[] args) {

        //Creating arraylist
        ArrayList<String> Companies = new ArrayList();

        // Adding new elements to the ArrayList
        Companies.add("Samsung");
        Companies.add("Apple");
        Companies.add("Motorola");
        Companies.add("Google");
        Companies.add("Sony");
        Companies.add("Blackberry");

        //Traversing list through Iterator
        for(String a:Companies)
            System.out.println(a);
        System.out.println("------------------------------------------");

        //Traversing list through for loop
        for(int i=0;i<Companies.size();i++)
        {
            System.out.println(Companies.get(i));
        }
        System.out.println("------------------------------------------");

        // Traversing list through For-Each loop
        for(String a:Companies)
            System.out.println(a);
    }
}

Java Tutorials

Java is a general-purpose programming language that is a concurrent, class-based, and object-oriented language. Java follows the concept of “write once and run anywhere (WORA).” This means that compiled Java code can be run on all different platforms that support Java. There’s no need for recompilation.

Eclipse IDE

Chapter 1 How to Download and Install Eclipse IDE
Chapter 2 How to Clone a project from GitLab using Eclipse
Chapter 3 How to Export Eclipse projects to GitLab

IntelliJ IDE

Chapter 1 How to install IntelliJ on Windows
Chapter 2 How to create a Java project in IntelliJ
Chapter 3 How to Clone a project from GitLab using IntelliJ
Chapter 4 How to Export IntelliJ project to GitLab

Basics of Java

Chapter 1 How to Download & Install Java JDK 11 in Windows
Chapter 2 Data Types and Operators in Java
Chapter 3 Decision Making in Java – If, If Else, Switch, Break, Continue
Chapter 4 Loop Control Statements in Java – For, While, Do While, Enhanched For Loop
Chapter 5 String Manipulation
Chapter 6 Difference between == and equals() method in Java
Chapter 7 Arrays in Java
Chapter 8 Java Access Modifiers: Explained with Examples
Chapter 9 ArrayList in Java
Chapter 10 How to compare ArrayLists – contains?
Chapter 11 How to compare ArrayLists – containsAll method?
Chapter 12 Methods in Java
Chapter 13 Method Overloading in Java
Chapter 14 Constructors in Java   
Chapter 15 This Keyword in Java   
Chapter 16 Static Keyword – Static Variable and Static Method in Java
Chapter 17 Difference between Static Method and Non-Static Method
Chapter 18 How to use Java Lambda expression to create thread via Runnable function
Chapter 19 runAsync and supplyAsync in ComputableFuture in Java8
Chapter 20 HashMap in Java
Chapter 21 LinkedHashMap in Java
Chapter 22 Iterators in Java

OOPs Concepts

Chapter 1 Class and Object in Java
Chapter 2 Inheritance in Java
Chapter 3 Encapsulation in Java
Chapter 4 Polymorphism in Java
Chapter 5 Abstraction in Java
Chapter 6 Interface in Java
Chapter 7 Difference between Abstract Class and Interface

Exceptions in Java

Chapter 1 Exception Handling in Java
Chapter 2 Java Exceptions Tutorial: Built-in and User-defined Exceptions
Chapter 3 Flow control in try catch finally in Java
Chapter 4 Multiple Catch Exceptions
Chapter 5 Throw in Java
Chapter 6 Throws in Java

Data Handling (Excel Manipulation)

Chapter 1 How to download and install Apache POI
Chapter 2 Reading Excel Data with Apache POI in Java
Chapter 3 How to Write Data to Excel File in Java using Apache POI
Chapter 4 How to update existing excel in Java
Chapter 5 Java Excel Tutorial: Creating Excel with Formulas Using Apache POI
Chapter 6 Change Font Style in Excel with Apache POI – NEW

Multiple Choice Questions

Chapter 1 Multiple questions on Exception Handling in Java

Java Library

Chapter 1 AssertJ – Fluent Assertions in Java

Allure Report with Cucumber, Selenium and TestNG

Last Updated On

HOME

In the previous tutorial, I explained the Integration of the Allure Report with Selenium and TestNG. In this tutorial, I will explain how to Integrate Allure Report with Cucumber, Selenium, and TestNG.

The below example covers the implementation of Allure Reports with Cucumber, Selenium, TestNG, Java, and Maven. Before starting, make sure to install Allure on your machine. Refer to this tutorial to install allure – What is Allure Report?.

Table of Contents

  1. Prerequisite
  2. Dependency List
  3. Implementation Steps
    1. Update the Properties section in Maven pom.xml
    2. Add Cucumber5, Selenium, TestNG, Allure-Cucumber5, and Allure-TestNG dependencies
    3. Update the Build Section of pom.xml in the Allure Report Project
    4. Create a Feature file
    5. Create the Step Definition class or Glue Code
    6. Create a TestNG Cucumber Runner class
    7. Create testng.xml for the project
    8. Run the Test and Generate Allure Report
  4. Allure Report Dashboard
    1. Categories in Allure Report
    2. Suites in Allure Report
    3. Graphs in Allure Report
    4. Timeline in Allure Report
    5. Behaviours of Allure Report
    6. Packages in Allure Report

Prerequisite

  1. Java 17 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed
  4. Allure installed

Dependency List

  1. Selenium – 4.16.1
  2. Java 17
  3. Cucumber – 7.15.0
  4. Maven – 3.9.6
  5. Allure Report – 2.25.0
  6. Allure Maven – 2.12.0
  7. Aspectj – 1.9.21
  8. Maven Compiler Plugin – 3.12.1
  9. Maven Surefire Plugin – 3.2.3

Implementation Steps

Step 1 – Update the Properties section in Maven pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.15.0</cucumber.version>
    <selenium.version>4.16.1</selenium.version>
    <testng.version>7.9.0</testng.version>
    <maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <allure.junit4.version>2.25.0</allure.junit4.version>
    <aspectj.version>1.9.21</aspectj.version>
    <allure.version>2.25.0</allure.version>
    <allure.maven>2.12.0</allure.maven>
</properties>

Step 2 – Add dependencies to pom.xml

Add Cucumber, Selenium, TestNG, Allure-Cucumber, and Allure-TestNG dependencies to pom.xml (Maven Project).

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-bom</artifactId>
        <version>${allure.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>


  <dependencies>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
    </dependency>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-testng</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- Selenium -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

    <!-- TestNG -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>${testng.version}</version>
      <scope>test</scope>
    </dependency>

    <!--Allure Cucumber Dependency-->
    <dependency>
      <groupId>io.qameta.allure</groupId>
      <artifactId>allure-cucumber7-jvm</artifactId>
      <scope>test</scope>
    </dependency>

    <!--Allure Reporting Dependency-->
    <dependency>
      <groupId>io.qameta.allure</groupId>
      <artifactId>allure-testng</artifactId>
      <scope>test</scope>
    </dependency>

  </dependencies>

Step 3 – Update the Build Section of pom.xml in the Allure Report Project

<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source.version}</source>
          <target>${maven.compiler.target.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
          <argLine>
            -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
          </argLine>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
            <scope>runtime</scope>
          </dependency>
        </dependencies>
      </plugin>
      <plugin>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-maven</artifactId>
        <version>${allure.maven}</version>
        <configuration>
          <reportVersion>${allure.maven}</reportVersion>
        </configuration>
      </plugin>
    </plugins>
  </build>

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>AllureReport_Cucumber_TestNG</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>AllureReport_Cucumber_TestNG</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.15.0</cucumber.version>
    <selenium.version>4.16.1</selenium.version>
    <testng.version>7.9.0</testng.version>
    <maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <allure.junit4.version>2.25.0</allure.junit4.version>
    <aspectj.version>1.9.21</aspectj.version>
    <allure.version>2.25.0</allure.version>
    <allure.maven>2.12.0</allure.maven>
  </properties>

  <!-- Add allure-bom to dependency management to ensure correct versions of all the dependencies are used -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-bom</artifactId>
        <version>${allure.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
    </dependency>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-testng</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- Selenium -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

    <!-- TestNG -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>${testng.version}</version>
      <scope>test</scope>
    </dependency>

    <!--Allure Cucumber Dependency-->
    <dependency>
      <groupId>io.qameta.allure</groupId>
      <artifactId>allure-cucumber7-jvm</artifactId>
      <scope>test</scope>
    </dependency>

    <!--Allure Reporting Dependency-->
    <dependency>
      <groupId>io.qameta.allure</groupId>
      <artifactId>allure-testng</artifactId>
      <scope>test</scope>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source.version}</source>
          <target>${maven.compiler.target.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
          <argLine>
            -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
          </argLine>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
            <scope>runtime</scope>
          </dependency>
        </dependencies>
      </plugin>
      <plugin>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-maven</artifactId>
        <version>${allure.maven}</version>
        <configuration>
          <reportVersion>${allure.maven}</reportVersion>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Step 4 – Create a Feature file

Create a folder – features within src/test/resources to create test scenarios in the Feature file.

Feature file should be saved as an extension of .feature. Add the test scenarios in this feature file. I have added sample test scenarios. In this feature file. The test scenarios are written in Gherkins language.

Feature: Login to HRM Application

  Background:
    Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"

  @ValidCredentials
  Scenario: Login with valid credentials

    When User enters username as "Admin" and password as "admin123"
    Then User should be able to login successfully and new page open

  @InvalidCredentials
  Scenario Outline: Login with invalid credentials

    When User enters username as "<username>" and password as "<password>"
    Then User should be able to see error message "<errorMessage>"

    Examples:
      | username   | password  | errorMessage                      |
      | Admin      | admin12$$ | Invalid credentials               |
      | admin$$    | admin123  | Invalid credentials               |
      | abc123     | xyz$$     | Invalid credentials               |
      | 234        | xyz$$     | Invalid credentials!              |

Step 5 – Create the Step Definition class or Glue Code

Below is the code for the Hooks.

package com.example.definitions;

import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.time.Duration;

public class Hooks {
    protected static WebDriver driver;
    public final static int TIMEOUT = 5;

    @Before
    public void setUp() {

        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        driver = new ChromeDriver(options);
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));

    }

    @After
    public void tearDown(Scenario scenario) {
        try {
            String screenshotName = scenario.getName();
            if (scenario.isFailed()) {
                TakesScreenshot ts = (TakesScreenshot) driver;
                byte[] screenshot = ts.getScreenshotAs(OutputType.BYTES);
                scenario.attach(screenshot, "img/png", screenshotName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        driver.quit();
    }

}

LoginPageDefinition

package com.example.definitions;


import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;

import org.openqa.selenium.By;
import org.testng.Assert;

public class LoginPageDefinitions {

   Hooks hooks;


    @Given("User is on HRMLogin page {string}")
    public void loginTest(String url) {

        hooks.driver.get(url);

    }

    @When("User enters username as {string} and password as {string}")
    public void goToHomePage(String userName, String passWord) {

        // login to application
        hooks.driver.findElement(By.name("username")).sendKeys(userName);
        hooks.driver.findElement(By.name("password")).sendKeys(passWord);
        hooks.driver.findElement(By.xpath("//*[@class='oxd-form']/div[3]/button")).submit();

        // go the next page
    }

    @Then("User should be able to login successfully and new page open")
    public void verifyLogin() {

        String homePageHeading = hooks.driver.findElement(By.xpath("//*[@class='oxd-topbar-header-breadcrumb']/h6")).getText();

        //Verify new page - HomePage
        Assert.assertEquals(homePageHeading,"Dashboard");

    }

    @Then("User should be able to see error message {string}")
    public void verifyErrorMessage(String expectedErrorMessage) {

        String actualErrorMessage = hooks.driver.findElement(By.xpath("//*[@class='orangehrm-login-error']/div[1]/div[1]/p")).getText();

        // Verify Error Message
        Assert.assertEquals(actualErrorMessage, expectedErrorMessage);

    }

}

Step 6 – Create a TestNG Cucumber Runner class

We need to create a class called Runner class to run the tests. This class will use the TestNG annotation @Test, which tells TestNG what is the test runner class.

package com.example.runner;

import org.testng.annotations.Test;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;


@Test
@CucumberOptions(tags = "", features = {"src/test/resources/features"}, glue = {"com.example.definitions"},
        plugin = {"pretty","io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm"})

public class CucumberRunnerTests extends AbstractTestNGCucumberTests{

}

Note:- @Test annotation marks this class as part of the test. So, if we will remove this annotation, the Allure Report executes CucumberRunnerTests as a separate test suite, so there will be duplicate results.

Step 7 – Create testng.xml for the project

<?xml version = "1.0"encoding = "UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "Suite1">
    <test name = "Test Demo">
        <classes>
            <class name = "com.example.runner.CucumberRunnerTests"/>
        </classes>
    </test>
</suite>

Step 8 – Run the Test and Generate Allure Report

To run the tests, use the below command

mvn clean test

In the below image, we can see that one test failed and four passed out of five tests.

This will create the allure-results folder with all the test reports within target folder. These files will be used to generate Allure Report.

Use the below command to generate the Allure Report

allure serve

This will generate the beautiful Allure Test Report as shown below.

Allure Report Dashboard

Categories in Allure Report

The categories tab gives you a way to create custom defect classifications to apply for test results. There are two categories of defects – Product Defects (failed tests) and Test Defects (broken tests).

Suites in Allure Report

On the Suites tab a standard structural representation of executed tests, grouped by suites and classes can be found. Here, we have 2 suits – Feature and Surefire test. Surefire tests are executed from CucumberRunnerTests.

Graphs in Allure Report

Graphs allow you to see different statistics collected from the test data: status breakdown or severity and duration diagrams.

Timeline in Allure Report

The timeline tab visualizes retrospective test execution, allure adaptors collect precise timings of tests, and here on this tab, they are arranged accordingly to their sequential or parallel timing structure.

Behaviours of Allure Report

This tab groups test results according to Epic, Feature, and Story tags.

Screenshot attached to the failed test case

Packages in Allure Report

The packages tab represents a tree-like layout of test results, grouped by different packages.

When we don’t use @Test in CucumberRunnerTests.java, then as mentioned above the Allure report will have duplicate details.

Congratulations!! We have integrated an allure report with Cucumber, Selenium, and TestNG. I hope this tutorial is useful to you.

Additional Tutorials on Allure Reports

Integration of Allure Report with Selenium and JUnit4
Integration of Allure Report with Selenium and TestNG
Gradle – Allure Report for Selenium and JUnit4
Gradle – Allure Report for Cucumber, Selenium and TestNG
Integration of Allure Report with Rest Assured and JUnit4

Difference between Static Method and Non-Static Method

HOME

package com.example.definitions;

public class staticMyClass {

    static void MyStatic_Method() { // Static Method
        System.out.println("Static method can be accessed without creating object");
    }

    public void MyPublic_Method() { // Public Method
        System.out.println("Public  method can be accessed only by creating object");
    }

    public static void main(String[] args) {
        MyStatic_Method(); // Calling Static Method

    }
}


public class nonStaticClass {

    static void MyStatic_Method() { // Static Method
        System.out.println("Static method can be accessed without creating object");
    }

    public void MyPublic_Method() { // Public Method
        System.out.println("Public method can be accessed only by creating object");
    }

    public static void main(String[] args) {

        nonStaticClass stat = new nonStaticClass();
        stat.MyPublic_Method();   // Calling Non Static Method


    }
}

How to manage driver executables using WebDriverManager

HOME

The traditional way to use any browser in Selenium tests is to download browser binaries, and we need to set the path of these files in our script like below or its location should be added to the classpath.

System.setProperty("webdriver.chrome.driver", "/absolute/path/to/binary/chromedriver");

The process of manually downloading and managing these drivers for each of the operating systems is very painful. We also have to check when new versions of the binaries are released / new browser versions are released. We should check the compatibility for all the executables and add them.

How to download all the driver executables automatically?

The automatic download of the drivers can be done by WebDriverManager. WebDriverManager is a library that allows controlling web browsers programmatically. It provides a cross-browser API that can be used to drive web browsers (e.g., Chrome, Edge, or Firefox, among others) using different programming languages (e.g., Java, JavaScript, Python, C#, or Ruby). The primary use of Selenium WebDriver is implementing automated tests for web applications.

The communication between the WebDriver API and the driver binary is done using a standard protocol called W3C WebDriver (formerly the so-called JSON Wire Protocol). Then, the communication between the driver and the browser is done using the native capabilities of each browser.

How To add WebDriverManager to a Selenium project manually?

Download the latest version of WebDriverManager from here.

It will download a zip file. Now extract the jar/zip file. It will show various .jar under the folder, as shown below:

Once we extract the zip file, we have to reference these jar files in our project. For this, navigate to project properties and click Build Path-> Configure Build Path in Eclipse

Click “Add External Jars” as per the steps highlighted below to include all the WebDriverManager jars extracted.

After clicking on the “Add External JARs“, all the selected extracted JARs are added to the project.

When this finishes, the project references show these referenced jars in the project explorer as highlighted below, and they are ready to be consumed in the Selenium test scripts.

Chrome

The below code snippet shows a quick usage of WebDriverManager with Chrome:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import io.github.bonigarcia.wdm.WebDriverManager;

public class Demo {

	public static void main(String[] args) {

		WebDriverManager.chromedriver().setup();

		// Create an object of Chrome Options class
		ChromeOptions chromeOptions = new ChromeOptions();

		// Create an object of WebDriver class and pass the Chrome Options object as
		// an argument
		WebDriver driver = new ChromeDriver(chromeOptions);

		System.out.println("Executing Chrome Driver");

		driver.get("https://www.bing.com/");
		System.out.println("Title of Page :" + driver.getTitle());
		System.out.println("Page URL : " + driver.getCurrentUrl());

		// Close the driver
		driver.close();

	}
}

The output of the above program is

FireFox Driver

The below code snippet shows a quick usage of WebDriverManager with FireFox:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

import io.github.bonigarcia.wdm.WebDriverManager;

public class FireFoxDemo {

	public static void main(String[] args) {

		WebDriverManager.firefoxdriver().setup();

		// Create an object of Firefox Options class
		FirefoxOptions firefoxOptions = new FirefoxOptions();

	    // Create an object of WebDriver class and pass the Firefox Options object
		// as an argument
		WebDriver driver = new FirefoxDriver(firefoxOptions);

		System.out.println("Executing Firefox Driver");

		driver.get("https://www.bing.com/");
		System.out.println("Title of Page :" + driver.getTitle());
		System.out.println("Page URL : " + driver.getCurrentUrl());

		// Close the driver
		driver.close();

	}
}

The output of the above program is

Microsoft Edge

The below code snippet shows a quick usage of WebDriverManager with Microsoft Edge:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import io.github.bonigarcia.wdm.WebDriverManager;

public class EdgeDemo {

	public static void main(String[] args) {

		WebDriverManager.edgedriver().setup();

		// Create an object of Edge Options class
		EdgeOptions edgeOptions = new EdgeOptions();

		// Create an object of WebDriver class and pass the Edge Options object
		// as an argument
		WebDriver driver = new EdgeDriver(edgeOptions);

		System.out.println("Executing Microsoft Edge Driver");

		driver.get("https://www.bing.com/");
		System.out.println("Title of Page :" + driver.getTitle());
		System.out.println("Page URL : " + driver.getCurrentUrl());

		// Close the driver
		driver.close();

	}
}

The output of the above program is

The basic use of these managers is the following:

WebDriverManager.chromedriver().setup();
WebDriverManager.firefoxdriver().setup();
WebDriverManager.edgedriver().setup();
WebDriverManager.operadriver().setup();
WebDriverManager.chromiumdriver().setup()
WebDriverManager.iedriver().setup();

How To add WebDriverManager to a Selenium project using Maven or Gradle?

To use WebDriverManager in a Maven built project, the below-mentioned dependency is needed to add to the pom.xml.

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

For Gradle project, add the below to the build.gradle.

dependencies {
    testCompile("io.github.bonigarcia:webdrivermanager:5.1.0")
}

How to instantiate a specific browser version using WebDriverManager?

WebDriverManager provides the ability to download a specific version of the browser. For example, the latest chromedriver version is 100.0.4896.20 (released on 2022-03-04). But if we want an earlier version, say, Chromedriver version 98.0.4758.102, we have to add the following code.

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

public class Demo {

	public static void main(String[] args) {

		WebDriverManager.chromedriver().driverVersion("98.0.4758.102").setup();

		// Create an object of Chrome Options class
		ChromeOptions chromeOptions = new ChromeOptions();

		// Create an object of WebDriver class and pass the Chrome Options object as
		// an argument
		WebDriver driver = new ChromeDriver(chromeOptions);

		System.out.println("Executing Chrome Driver");

		driver.get("https://www.bing.com/");
		System.out.println("Title of Page :" + driver.getTitle());
		System.out.println("Page URL : " + driver.getCurrentUrl());

		// Close the driver
		driver.close();

	}
}

The output of the above program is

As we can see from the above screenshot, as a result of executing the above program, the Chromedriver started successfully. We can see the details of starting the chrome driver instance in the first line of output. Here we have set the Chrome version to 98.0.4758.102″.

Congratulations!! We have learned to download drivers automatically.

Data Driven Tests using CSV file in Serenity

HOME

In the previous tutorial, I have explained the Data Driven Tests in Serenity where test data are defined in Tests. In this tutorial, I will explain the Data Driven tests in Serenity where we will get the test data from CSV file.

To start with this tutorial, refer this tutorial also which explains how to setup a project with Serenity and JUnit4.

Project Structure

Serenity lets us perform data-driven testing using test data in a CSV file. We store our test data in a CSV file (by default with columns separated by commas), with the first column acting as a header.

We need to create a test class containing properties that match the columns in the test data, as you did for the data-driven test in the previous example. The test class will typically contain one or more tests that use these properties as parameters to the test step or Page Object methods.

Here, we need to keep in mind that as the tests are parameterized , we need to use the Parameterized test runner to perform data-driven tests.

@RunWith(SerenityParameterizedRunner.class)

This is imported from below package

net.serenitybdd.junit.runners.SerenityParameterizedRunner;

@UseTestDataFrom annotation is used to indicate where to find the CSV file (this can either be a file on the classpath or a relative or absolute file path – putting the data set on the class path (e.g. in src/test/resources) makes the tests more portable).

@UseTestDataFrom(value = "testdata/credentials.csv")

Below is the example of the Parameterized Tests.

ParameterizedTestsUsingCSV Class contains the SerenityParameterizedRunner as well as provides the path of the test data file using @UseTestDataFrom, and the Tests.

The Serenity Parameterized Runner creates a new instance of this class for each row of data in the CSV file, assigning the properties with corresponding values in the test data. As you can see, I have mentioned 3 variables in the CSV file – userName, passWord, and errorMessage. I have declared the same private variables in the Test Class too – username, password, and errorMessage that match the columns in the test data file. Keep this in mind, that the column name should be the same in test data file and Test.

import net.serenitybdd.annotations.Managed;
import net.serenitybdd.annotations.Steps;
import net.serenitybdd.annotations.Title;
import net.serenitybdd.core.Serenity;
import net.serenitybdd.junit.runners.SerenityParameterizedRunner;
import net.thucydides.junit.annotations.Qualifier;
import net.thucydides.junit.annotations.TestData;
import net.thucydides.junit.annotations.UseTestDataFrom;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SerenityParameterizedRunner.class)
@UseTestDataFrom(value = "testdata/credentials.csv")
public class ParameterizedTests {

    private String userName;
    private String passWord;
    private String errorMessage;

    @Managed(options = "--start-maximized")
     WebDriver driver;

    @Steps
    NavigateActions navigate;

    @Steps
    StepLoginPage loginPage;


    @TestData(columnNames = "Username, Password, ErrorMessage")

    @Qualifier
    public String qualifier(){return " - " + " Username = " + userName + " and " + " Password = " + passWord + " should display " + errorMessage;}

    @Test
    @Title("Login to application with invalid credential generates error message")
    public void unsuccessfulLogin() {

        // Given
        navigate.toTheHomePage();

        // When
        loginPage.inputUserName(userName);
        loginPage.inputPassword(passWord);
        loginPage.clickLogin();

        // Then
        Serenity.reportThat("Passing invalid credentials generates error message",
                () -> assertThat(assertThat(loginPage.errorMessage()).isEqualToIgnoringCase(errorMessage)));

    }

}

The heading of parameters present in the Serenity Report (Index.html) like Username, Password, and Error Message are generated by @TestData(columnNames).

The description of the Test Step in the Serenity Report is modified by using @Qualifier. It is used to mark a method as a qualifier in an instantiated data-driven test case.

The test class needs to have a WebDriver instance with a @Managed annotation for Serenity to manage it in the background. That is all that is required, we do not need to manage the driver anymore. Each test class will need this driver variable declaration.

The Test Class uses Step Class (StepLoginPage) and Action Class (NavigateActions) to perform the Tests. StepLoginPage contains test steps that represent the level of abstraction between the code that interacts with the application. NavigateAction page is used to open an environment-specific page defined in the serenity.config file under the pages section.

StepLoginPage

import net.serenitybdd.annotations.Step;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;
import org.openqa.selenium.support.FindBy;

public class StepLoginPage extends PageObject {

    @FindBy(name = "username")
    WebElementFacade username;

    @FindBy(name = "password")
    WebElementFacade password;

    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
    WebElementFacade submitButton;

    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
    WebElementFacade errorMessage;

    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[4]/p")
    WebElementFacade linkText;

    @Step("Enter Username")
    public void inputUserName(String userName) {
        username.sendKeys((userName));
    }

    @Step("Enter Password")
    public void inputPassword(String passWord) {
        password.sendKeys((passWord));
    }

    @Step("Click Submit Button")
    public void clickLogin() {
        submitButton.click();
    }

    @Step("Error Message on unsuccessful login")
    public String errorMessage() {
        String actualErrorMessage = errorMessage.getText();
        return actualErrorMessage;
    }

    @Step("Click Forget Password Link")
    public void clickForgetPasswordLink() {
        linkText.click();

        System.out.println("Clicked on Forgot Password Link");
    }

}

NavigateActions

import net.serenitybdd.annotations.Step;
import net.serenitybdd.core.steps.UIInteractionSteps;

public class NavigateActions extends UIInteractionSteps {

    @Step
    public void toTheHomePage() {
        openPageNamed("loginForm");
    }
}

Serenity.config

headless.mode = false

pages{
  loginForm = "https://opensource-demo.orangehrmlive.com/"
  }

environments {
  chrome {
    webdriver {
      driver = chrome
      autodownload = true
      capabilities {
        browserName = "chrome"
        acceptInsecureCerts = true
        "goog:chromeOptions" {
          args = ["--start-maximized", "ignore-certificate-errors",
            "incognito", "disable-infobars", "disable-gpu", "disable-default-apps", "disable-popup-blocking"]
        }
      }
    }
  }
}

This test can be executed by JUnit as well as from the command line

JUnit – Right-click on the Test, select Run As, and then select JUnit Test in Eclipse.

If you are using IntelliJ, then right-click and select Run “ParameterizedTests”

The Test execution status can be seen as shown below:

To run the tests using the command line, use the below command

mvn clean verify

This will execute the tests and will generate the Test Execution Report as shown below.

The reports are generated as shown in the below image.

Serenity generates very descriptive and beautiful reports – Index.html and Serenity Summary Report.

Index.html

This page provides the detail about the Test, its corresponding test data, the status of each test scenario with screenshots, and the execution time of each test.

This is the expanded view of all the test steps of a test with their screenshots. This also shows the execution time of each step in the test.

Serenity Summary Report

This report is a single-page, self-contained HTML summary report, containing an overview of the test results, and a configurable breakdown of the status of different areas of the application.

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Run Cucumber Test from Maven Command Line

Last Updated on

HOME

To have a successful and effective implementation of a test framework, it is always advisable that the test framework supports test execution in multiple ways.
The most commonly used ways to execute tests in Cucumber Framework are by running the tests using JUnit and TestNG.

To execute tests using JUnit, we need to create a JUnit Test Runner. Whereas, we need a Maven project to execute Cucumber tests from Command-Line.

Create a Maven project and add the below-mentioned dependencies to your Maven project.

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>Cucumber_TestNG_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>Cucumber_TestNG_Demo</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.15.0</cucumber.version>
    <selenium.version>4.16.1</selenium.version>
    <testng.version>7.9.0</testng.version>
    <maven.compiler.plugin.version>3.12.1</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
    </dependency>

    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-testng</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- Selenium -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

    <!-- TestNG -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>${testng.version}</version>
      <scope>test</scope>
    </dependency>

  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source.version}</source>
          <target>${maven.compiler.target.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Feature: Login to HRM Application

  Background:
    Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"

  @ValidCredentials
  Scenario: Login with valid credentials

    When User enters username as "Admin" and password as "admin123"
    Then User should be able to login successfully

  @InvalidCredentials
  Scenario Outline: Login with invalid credentials

    When User enters username as "<username>" and password as "<password>"
    Then User should be able to see error message "<errorMessage>"

    Examples:
      | username   | password  | errorMessage                      |
      | Admin      | admin12$$ | Invalid credentials               |
      | admin$$    | admin123  | Invalid credentials               |
      | abc123     | xyz$$     | Invalid credentials               |

Feature: Login to Home

  Background:
    Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"

  @ValidCredentialsHome
  Scenario: Login with valid credentials to got to home page

    When User enters username as "Admin" and password as "admin123"
    Then User should be able to login successfully and new Home page opens

Run Test from Command Line

1. Open the command prompt and change the directory to the project location where pom.xml is present.

C:\Users\Documents\Vibha\Automation\Cucumber_Selenium_TestNG

2. All feature files should be in src/test/resources and create the Cucumber Runner class as CucumberRunnerTest.
Note:- The Runner class name should end with Test to execute the tests from Command Line
Run the following command in the command prompt:

mvn clean test

mvn clean test runs Cucumber Features using Cucumber’s JUnit Runner. The @RunWith (Cucumber.class) annotation on the TestRunner class tells JUnit to start Cucumber. Cucumber runs time parses the command-line options to know what feature to run, where the Glue Code lives, what plugins to use, and so on.

3. The below screenshot shows that CucumberRunnerTest class is triggered.

4. The below screenshot shows the build success output.

Cucumber provides several options that can be passed to on the command line.

2. Running Scenarios using Tags

If you are using Maven and want to run a subset of scenarios tagged with @ValidCredentials.

mvn clean test -Dcucumber.filter.tags="@ValidCredentials"

3. Running a Feature file

Suppose you want to run a single Feature File from the command line, then use the below syntax

mvn clean test -Dcucumber.features="src/test/resources/features/HomePage.feature"

4. Creating Cucumber Report from Command Line

If we want to generate a different report, then we can use the following command and see the HTML report generate at the location mentioned:

mvn clean test -Dcucumber.plugin="html:target/cucumber-reports/cucumberReport.html"

5. Passing multiple Parameters

If we want to pass more than one parameter, then we can use the following command

mvn clean test -Dcucumber.features="src/test/resources/features/LoginPage.feature" -Dcucumber.filter.tags="@ValidCredentials"

6. Running a Scenario without a tag

If we want to run a single Scenario from the command line and no tag is assigned to that scenario, this is how we specify

mvn clean test -Dcucumber.features="src/test/resources/features/LoginPage.feature:7"

That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

In the next tutorial, I explained to run Cucumber Gradle tests from Command Line.

How to run Rest API tests with GitHub Actions

Last Updated On

HOME

This tutorial explains the steps to create a GitHub Action for the Java Rest API tests and execute the tests in that workflow.

Table of Contents

Why GitHub?

GitHub serves as a collaborative platform that supports version control, code collaboration, automated testing, and issue tracking, all of which are crucial elements in the software testing process. It promotes transparency, collaboration, and efficiency in the development and testing workflows.

CI/CD pipelines have contributed to the success of the DevOps cycle in all software development projects. This is a holistic process that bridges development and operations. Continuous integration helps development teams deploy code efficiently, and continuous delivery automates code deployment.

Implementation Steps

Step 1 – Create GitHub Actions and Workflows

I have a repository available in GitHub – RestAssured_TestNG_Demo as shown in the below image. Go to the “Actions” tab.  Click on the “Actions” tab.

Step 2 – Select the type of Actions

You will see that GitHub recommends Actions depending on the project. In our case, it is recommending actions suitable for a Java project. I have selected the “Java with Maven” option as my project is built in Maven.

Step 3 – Generation of Sample pipeline

If you choose an existing option, it will automatically generate a .yaml for the project as shown below.

We will replace the current workflow with the following yml file as shown below:

name: Rest API Tests using Rest Assured with TestNG
 
on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]
 
jobs:
  build:
 
    runs-on: ubuntu-latest
 
    steps:
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
        cache: maven
     
    - name: Test Execution
      run: mvn clean test
       
    - name: Test Report Generation
      uses: actions/upload-artifact@v4
      if: success() || failure()
      with:
          name: TestNG Report                 # Name of the folder
          path: target/surefire-reports/      # Path to test results

Step 4 – Commit the changes

After the changes, hit the “Start Commit” button.

This will give the option to add a description for the commit. It will also enable the user to commit either to the main branch or commit to any other branch that exists in the project. Click on the “Commit new file” button to set up the workflow file.

Step 5 – Verify that the workflow is running

Next, head over to the “Actions” tab, and you will see your YAML workflow file present under the tab. The yellow sign represents that the job is in the queue.

In Progress – When the job starts building and running, you will see the status change from “Queued” to “in progress”.

Passed – If the build is successful, you will see a green tick mark. 

Click on the workflow and the below screen is displayed. It shows the status of the run of the workflow, the total time taken to run the workflow, and the name of the .yml file.

Below shows all the steps of the workflow.

The complete code can be found here on GitHub – vibssingh/RestAssured_TestNG_Demo.

Congratulations! We just created our CI workflow for running our Rest API test cases.