How to create and write JSON with JSON.simple in Java

HOME

This article shows how to write a JSON using JSON.simple.

JSON.simple is available at the Central Maven Repository. Maven users add this to the POM.

<!-- https://mvnrepository.com/artifact/com.github.cliftonlabs/json-simple -->
<dependency>
    <groupId>com.github.cliftonlabs</groupId>
    <artifactId>json-simple</artifactId>
    <version>4.0.1</version>
</dependency>

If the project is Gradle, add the below dependency in build.gradle.

// https://mvnrepository.com/artifact/com.github.cliftonlabs/json-simple
implementation("com.github.cliftonlabs:json-simple:4.0.1")

Write Simple JSON to File using JSON.simple

{ 
    "Working Days":[ 
                             "Monday",
                             "Tuesday",
                             "Wednesday"
                             ],
    "Salary":4500.0,
    "Name":"Vibha"
}

import com.github.cliftonlabs.json_simple.JsonArray;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;

import java.io.FileWriter;
import java.io.IOException;

public class WriteSimpleJson {
    public static void main(String[] args) {

        // JSON String
        JsonObject jsonObject = new JsonObject();
        jsonObject.put("Name", "Vibha");
        jsonObject.put("Salary", 4500.00);

        // JSON Array
        JsonArray list = new JsonArray();
        list.add("Monday");
        list.add("Tuesday");
        list.add("Wednesday");

        jsonObject.put("Working Days", list);
        System.out.println(Jsoner.serialize(jsonObject));

        try (FileWriter fileWriter = new FileWriter("src/test/resources/Payloads/Employee.json")) {
            Jsoner.serialize(jsonObject, fileWriter);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

JsonObject jsonObject = new JsonObject();
jsonObject.put("Name", "Vibha");
jsonObject.put("Salary", 4500.00);
JsonArray list = new JsonArray();
list.add("Monday");
list.add("Tuesday");
list.add("Wednesday");
jsonObject.put("Working Days", list);
 try (FileWriter fileWriter = new FileWriter("src/test/resources/Payloads/Employee.json")) {
            Jsoner.serialize(jsonObject, fileWriter);

  } 

{
  "Working Days": ["Monday","Tuesday","Wednesday"],
  "Salary":{
    "Bonus":{
      "Quaterly":125.0,
      "Monthly":45.0,
      "Yearly":500.0
    },
    "Fixed":4000.0
  },"Name": {
  "Forename":"Vibha",
  "Surname":"Singh"
 }
}

import com.github.cliftonlabs.json_simple.JsonArray;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;

import java.io.FileWriter;
import java.io.IOException;

public class WriteComplexJson {

    public static void main(String[] args) {

        JsonObject jsonObject = new JsonObject();

        //Name
        JsonObject name = new JsonObject();
        name.put("Forename", "Vibha");
        name.put("Surname", "Singh");
        jsonObject.put("Name", name);

        //Salary
        JsonObject salary = new JsonObject();
        salary.put("Fixed", 4000.00);

        //Bonus
        JsonObject bonus = new JsonObject();
        bonus.put("Monthly", 45.00);
        bonus.put("Quaterly", 125.00);
        bonus.put("Yearly", 500.00);

        salary.put("Bonus",  bonus);
        jsonObject.put("Salary", salary);

        // JSON Array
        JsonArray list = new JsonArray();
        list.add("Monday");
        list.add("Tuesday");
        list.add("Wednesday");
        jsonObject.put("Working Days", list);

        System.out.println(Jsoner.serialize(jsonObject));

        try (FileWriter fileWriter = new FileWriter("src/test/resources/Payloads/EmployeeDetails.json")) {
            Jsoner.serialize(jsonObject, fileWriter);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 JsonObject jsonObject = new JsonObject();
JsonObject name = new JsonObject();
name.put("Forename", "Vibha");
name.put("Surname", "Singh");
jsonObject.put("Name", name);
//Salary
JsonObject salary = new JsonObject();
salary.put("Fixed", 4000.00);
//Bonus
JsonObject bonus = new JsonObject();
bonus.put("Monthly", 45.00);
bonus.put("Quaterly", 125.00);
bonus.put("Yearly", 500.00);

salary.put("Bonus",  bonus);
jsonObject.put("Salary", salary);
// JSON Array
JsonArray list = new JsonArray();
list.add("Monday");
list.add("Tuesday");
list.add("Wednesday");

jsonObject.put("Working Days", list);
jsonObject.put("Working Days", list);
System.out.println(Jsoner.serialize(jsonObject));

7. Writing the JSON to a File

The `try-with-resources` statement is used to ensure the `FileWriter` is closed automatically. A `FileWriter` writes the serialized JSON object to a file at `src/test/resources/Payloads/EmployeeDetails.json`.

 try (FileWriter fileWriter = new FileWriter("src/test/resources/Payloads/Employee.json")) {
            Jsoner.serialize(jsonObject, fileWriter); }

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

How to Read JSON with JSON.simple

HOME

This article shows how to read JSON using JSON.simple.

JSON.simple is available at the Central Maven Repository. Maven users add this to the POM.

<!-- https://mvnrepository.com/artifact/com.github.cliftonlabs/json-simple -->
<dependency>
    <groupId>com.github.cliftonlabs</groupId>
    <artifactId>json-simple</artifactId>
    <version>4.0.1</version>
</dependency>

If the project is Gradle, add the below dependency in build.gradle.

// https://mvnrepository.com/artifact/com.github.cliftonlabs/json-simple
implementation("com.github.cliftonlabs:json-simple:4.0.1")

Read Simple JSON from File using JSON.simple

{
  "store": {
    "book": "Harry Potter",
    "author": "J K Rowling",
    "price": 100
  }
}

import com.github.cliftonlabs.json_simple.JsonException;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;

public class SimpleJsonExample {

    public static void main(String args[]) throws IOException {

        String jsonString = new String(Files.readAllBytes(Paths.get("src/test/resources/Payloads/simple.json")));
        try {
            JsonObject jsonObject = (JsonObject) Jsoner.deserialize(jsonString);

            // Accessing the "store" object
            JsonObject store = (JsonObject) jsonObject.get("store");

            // Accessing the "book" object
            String book = (String) store.get("book");
            System.out.println("Book: " + book);

            // Accessing the "author" object
            String author = (String) store.get("author");
            System.out.println("Author - " + author);

            // Accessing the "price" field
            BigDecimal price = (BigDecimal) store.get("price");
            System.out.println("Price: " + price);

        } catch (JsonException e) {
            throw new RuntimeException(e);
        }
    }
}

String jsonString = new String(Files.readAllBytes(Paths.get("src/test/resources/Payloads/simple.json")));
JsonObject jsonObject = (JsonObject) Jsoner.deserialize(jsonString);
 JsonObject store = (JsonObject) jsonObject.get("store");
String book = (String) store.get("book");
System.out.println("Book: " + book);
String author = (String) store.get("author");
System.out.println("Author - " + author);
BigDecimal price = (BigDecimal) store.get("price");
System.out.println("Price: " + price);

public class ComplexJsonExample {

    public static void main(String args[]) throws IOException {

        String jsonString = new String(Files.readAllBytes(Paths.get("src/test/resources/Payloads/complex.json")));
        try {
            JsonObject jsonObject = (JsonObject) Jsoner.deserialize(jsonString);

            // Accessing the "store" object
            JsonObject store = (JsonObject) jsonObject.get("store");

            // Accessing the "book" array
            JsonArray books = (JsonArray) store.get("book");
            for (Object bookObj : books) {
                JsonObject book = (JsonObject) bookObj;
                String category = (String) book.get("category");
                String author = (String) book.get("author");
                String title = (String) book.get("title");
                BigDecimal price = (BigDecimal) book.get("price");

                System.out.println("Book: " + title + " (Category: " + category + ", Author: " + author + ", Price: " + price + ")");
            }

            // Accessing the "bicycle" object
            JsonObject bicycle = (JsonObject) store.get("bicycle");
            String color = (String) bicycle.get("color");
            BigDecimal bicyclePrice = (BigDecimal) bicycle.get("price");
            System.out.println("Bicycle: Color - " + color + ", Price - " + bicyclePrice);

            // Accessing the "expensive" field
            BigDecimal expensiveValue = (BigDecimal) jsonObject.get("expensive");
            System.out.println("Expensive threshold: " + expensiveValue);

        } catch (JsonException e) {
            throw new RuntimeException(e);
        }
    }
}
String jsonString = new String(Files.readAllBytes(Paths.get("src/test/resources/Payloads/complex.json")));
JsonObject jsonObject = (JsonObject) Jsoner.deserialize(jsonString);
 // Accessing the "store" object
JsonObject store = (JsonObject) jsonObject.get("store");

// Accessing the "book" array
JsonArray books = (JsonArray) store.get("book");
 for (Object bookObj : books) {
       JsonObject book = (JsonObject) bookObj;
       String category = (String) book.get("category");
       String author = (String) book.get("author");
       String title = (String) book.get("title");
       BigDecimal price = (BigDecimal) book.get("price");

        System.out.println("Book: " + title + " (Category: " + category + ", Author: " + author + ", Price: " + price + ")");
      }
 // Accessing the "bicycle" object
 JsonObject bicycle = (JsonObject) store.get("bicycle");
String color = (String) bicycle.get("color");
BigDecimal bicyclePrice = (BigDecimal) bicycle.get("price");
System.out.println("Bicycle: Color - " + color + ", Price - " + bicyclePrice);
BigDecimal expensiveValue = (BigDecimal) jsonObject.get("expensive");
System.out.println("Expensive threshold: " + expensiveValue);

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

Mastering CSV File Handling in Java with OpenCSV

HOME

<dependency>
            <groupId>com.opencsv</groupId>
            <artifactId>opencsv</artifactId>
            <version>5.10</version>
</dependency>

// https://mvnrepository.com/artifact/com.opencsv/opencsv
implementation group: 'com.opencsv', name: 'opencsv', version: '5.10'

  FileReader fileReader = new FileReader(filePath);
CSVReader csvReader = new CSVReader(fileReader);
List<String[]> records = csvReader.readAll();
  for (String[] record : records) {
                for (String field : record) {
                    System.out.print(field + " ");
                }
                System.out.println();
         }

package org.example;

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CSVReader_Demo {

    public static void main(String[] args) {

        String filePath = "C:\\Users\\Documents\\csv_test.csv";

        try {

            FileReader fileReader = new FileReader(filePath);
            CSVReader csvReader = new CSVReader(fileReader);
            List<String[]> records = csvReader.readAll();
            for (String[] record : records) {
                for (String field : record) {
                    System.out.print(field + " ");
                }
                System.out.println();
            }
        } catch (IOException | CsvException e) {
            System.err.println("Error reading CSV file: " + e.getMessage());
        }
    }
}

CSVReader csvReader = new CSVReaderBuilder(fileReader)
                    .withSkipLines(1)
                    .build();

package org.example;

import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CSVReader_LineSkip_Demo {

    public static void main(String[] args) {

        String filePath = "C:\\Users\\Documents\\csv_test.csv";

        try {
            FileReader fileReader = new FileReader(filePath);
            CSVReader csvReader = new CSVReaderBuilder(fileReader)
                    .withSkipLines(1)
                    .build();

            List<String[]> records = csvReader.readAll();
            for (String[] record : records) {
                for (String field : record) {
                    System.out.print(field + " ");
                }
                System.out.println();
            }
        } catch (IOException | CsvException e) {
            System.err.println("Error reading CSV file: " + e.getMessage());
        }
    }
}

CSVParser csvParser = new CSVParserBuilder().withSeparator(',').build();
CSVReader csvReader = new CSVReaderBuilder(fileReader).withCSVParser(csvParser).build();
package org.example;

import com.opencsv.CSVParser;
import com.opencsv.CSVParserBuilder;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;

import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CSVReader_Seperator_Demo {

    public static void main(String[] args) {

        String filePath = "C:\\Users\\Documents\\csv_test.csv";

        try {
            FileReader fileReader = new FileReader(filePath);
            CSVParser csvParser = new CSVParserBuilder().withSeparator(',').build();
            CSVReader csvReader = new CSVReaderBuilder(fileReader).withCSVParser(csvParser).build();

            List<String[]> records = csvReader.readAll();
            for (String[] record : records) {
                for (String field : record) {
                    System.out.print(field + " ");
                }
                System.out.println();
            }
        } catch (IOException | CsvException e) {
            System.err.println("Error reading CSV file: " + e.getMessage());
        }
    }
}

Run ChainTest Report on Docker

HOME

docker-compose -f docker-compose-h2.yml up

# chaintest configuration
chaintest.project.name= ChaninTest Report with Cucumber and TestNG

# generators:
## chainlp
chaintest.generator.chainlp.enabled=true
chaintest.generator.chainlp.class-name=com.aventstack.chaintest.generator.ChainLPGenerator
chaintest.generator.chainlp.host.url=http://localhost/
chaintest.generator.chainlp.client.request-timeout-s=30
chaintest.generator.chainlp.client.expect-continue=false
chaintest.generator.chainlp.client.max-retries=3
mvn clean test

ChainTest Report with Selenium and JUnit5

HOME

<dependency>
      <groupId>com.aventstack</groupId>
      <artifactId>chaintest-junit5</artifactId>
      <version>${chaintest.version}</version>
</dependency>

<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>ChainTestReport_JUnit5_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <selenium.version>4.21.0</selenium.version>
    <chaintest.version>1.0.11</chaintest.version>
    <junit.jupiter.engine.version>5.11.0-M2</junit.jupiter.engine.version>
    <junit.jupiter.api.version>5.11.0-M2</junit.jupiter.api.version>
    <junit.jupiter.params.version>5.11.0-M2</junit.jupiter.params.version>
    <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <maven.surefire.plugin.version>3.2.5</maven.surefire.plugin.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>

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

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>${junit.jupiter.engine.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>${junit.jupiter.api.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>${junit.jupiter.params.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.aventstack</groupId>
      <artifactId>chaintest-junit5</artifactId>
      <version>${chaintest.version}</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>

        <dependencies>
          <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.engine.version}</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

</project>

package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;

public class BasePage {
    public WebDriver driver;

    public BasePage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver,this);
    }

}

package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPage extends BasePage {

    public LoginPage(WebDriver driver) {
        super(driver);

    }

    @FindBy(name = "username")
    public WebElement userName;

    @FindBy(name = "password")
    public WebElement password;

    @FindBy(xpath = "//*[@type='submit']")
    public WebElement loginBtn;

    @FindBy(xpath = "//*[@id='flash']")
    public WebElement errorMessage;

    public void login(String strUserName, String strPassword) {
        userName.sendKeys(strUserName);
        password.sendKeys(strPassword);
        loginBtn.click();
    }

    public String getErrorMessage() {
        return errorMessage.getText();
    }

}
package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class SecurePage extends BasePage {

    public SecurePage(WebDriver driver) {
        super(driver);

    }

    @FindBy(xpath = "//*[@id='flash']")
    public WebElement securePageTitle;

    public String getSecurePageTitle() {
        return securePageTitle.getText();
    }

}
package com.example;

import com.aventstack.chaintest.plugins.ChainTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.TestWatcher;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import java.time.Duration;

@ExtendWith(ChainTestExecutionCallback.class)
public class BaseTests implements TestWatcher {

    public static WebDriver driver;
    public final static int TIMEOUT = 10;

    @BeforeEach
    public void setup() {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--remote-allow-origins=*");
        options.addArguments("--no-sandbox");
        options.addArguments("--disable-dev-shm-usage");
        driver = new ChromeDriver(options);

        driver.manage().window().maximize();
        driver.get("https://the-internet.herokuapp.com/login");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
    }

    @AfterEach
    void tearDown() {
        driver.quit();
    }

}

package com.example;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class LoginPageTests extends BaseTests {

    String actualLoginPageTitle;
    String actualErrorMessage;
    String actualSecurePageTitle;
    
    @Test
    public void verifyPageTitle() {

        actualLoginPageTitle = driver.getTitle();
        
        // Verify Page Title - Fail
        Assertions.assertEquals("The Internet !!",actualLoginPageTitle);

    }

    @Test
    public void invalidCredentials() {

        LoginPage loginPage = new LoginPage(driver);
        loginPage.login("tomsmith", "happy!");
        actualErrorMessage = loginPage.getErrorMessage();

        // Verify Error Message
        Assertions.assertTrue(actualErrorMessage.contains("Your password is invalid!"));

    }

    @Test
    public void validLogin() {

        LoginPage loginPage = new LoginPage(driver);
        loginPage.login("tomsmith", "SuperSecretPassword!");

        SecurePage securePage = new SecurePage(driver);
        actualSecurePageTitle = securePage.getSecurePageTitle();

        // Verify Home Page
        Assertions.assertTrue(actualSecurePageTitle.contains("You logged into a secure area!"));

    }
}

# chaintest configuration
chaintest.project.name= ChaninTest Report with Selenium and JUnit5

# storage
chaintest.storage.service.enabled=false
# [azure-blob, aws-s3]
chaintest.storage.service=azure-blob
# s3 bucket or azure container name
chaintest.storage.service.container-name=

# generators:
## chainlp
chaintest.generator.chainlp.enabled=true
chaintest.generator.chainlp.class-name=com.aventstack.chaintest.generator.ChainLPGenerator
chaintest.generator.chainlp.host.url=http://localhost/
chaintest.generator.chainlp.client.request-timeout-s=30
chaintest.generator.chainlp.client.expect-continue=false
chaintest.generator.chainlp.client.max-retries=3

## simple
chaintest.generator.simple.enabled=true
chaintest.generator.simple.document-title=chaintest
chaintest.generator.simple.class-name=com.aventstack.chaintest.generator.ChainTestSimpleGenerator
chaintest.generator.simple.output-file=target/chaintest/Index.html
chaintest.generator.simple.offline=false
chaintest.generator.simple.dark-theme=true
chaintest.generator.simple.datetime-format=yyyy-MM-dd hh:mm:ss a
chaintest.generator.simple.js=
chaintest.generator.simple.css=

## email
chaintest.generator.email.enabled=true
chaintest.generator.email.class-name=com.aventstack.chaintest.generator.ChainTestEmailGenerator
chaintest.generator.email.output-file=target/chaintest/Email.html
chaintest.generator.email.datetime-format=yyyy-MM-dd hh:mm:ss a

This report contains the high level summary of the test execution.

mvn clean test

ChainTest Report with Cucumber and TestNG

HOME

<dependency>
      <groupId>com.aventstack</groupId>
      <artifactId>chaintest-cucumber-jvm</artifactId>
      <version>${chaintest.cucumberjvm.version}</version>
      <scope>provided</scope>
 </dependency>

<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>ChainTestReport_Cucumber_TestNG_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.18.1</cucumber.version>
    <selenium.version>4.25.0</selenium.version>
    <testng.version>7.10.2</testng.version>
    <chaintest.cucumberjvm.version>1.0.11</chaintest.cucumberjvm.version>
    <apache.common.version>2.4</apache.common.version>
    <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.3.1</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <maven.cucumber.reporting.version>5.8.2</maven.cucumber.reporting.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>

    <dependency>
      <groupId>com.aventstack</groupId>
      <artifactId>chaintest-cucumber-jvm</artifactId>
      <version>${chaintest.cucumberjvm.version}</version>
      <scope>provided</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>
          <testFailureIgnore>true</testFailureIgnore>
          <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 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    |

  @MissingUsername
  Scenario: Login with blank username - FailedTest

    When User enters username as " " and password as "admin123"
    Then User should be able to see a message "Required1" below Username

package com.example.actions;

import com.example.locators.LoginPageLocators;
import org.openqa.selenium.support.PageFactory;
import com.example.utils.HelperClass;


public class LoginPageActions {

    LoginPageLocators loginPageLocators = null;

    public LoginPageActions() {

        this.loginPageLocators = new LoginPageLocators();
        PageFactory.initElements(HelperClass.getDriver(), loginPageLocators);
    }

    // Get the error message when username is blank
    public String getMissingUsernameText() {
        return loginPageLocators.missingUsernameErrorMessage.getText();
    }

    // Get the Error Message
    public String getErrorMessage() {
        return loginPageLocators.errorMessage.getText();
    }

    public void login(String strUserName, String strPassword) {

        // Fill user name
        loginPageLocators.userName.sendKeys(strUserName);

        // Fill password
        loginPageLocators.password.sendKeys(strPassword);

        // Click Login button
        loginPageLocators.login.click();

    }
}

package com.example.actions;

import com.example.locators.HomePageLocators;
import org.openqa.selenium.support.PageFactory;
import com.example.utils.HelperClass;

public class HomePageActions {

    HomePageLocators homePageLocators = null;

    public HomePageActions() {

        this.homePageLocators = new HomePageLocators();
        PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
    }

    public String getHomePageText() {
        System.out.println("Heading :" + homePageLocators.homePageUserName.getText());
        return homePageLocators.homePageUserName.getText();
    }

}
package com.example.locators;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPageLocators {

    @FindBy(name = "username")
    public WebElement userName;

    @FindBy(name = "password")
    public WebElement password;

    @FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
    public WebElement missingUsernameErrorMessage;

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

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

}

package com.example.locators;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePageLocators {

    @FindBy(xpath = "//span[@class='oxd-topbar-header-breadcrumb']/h6")

    public  WebElement homePageUserName;

}

package com.example.utils;

import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class HelperClass {

    private static HelperClass helperClass;

    private static WebDriver driver;
    public final static int TIMEOUT = 5;

    private HelperClass() {

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

    public static void openPage(String url) {
        driver.get(url);
    }

    public static WebDriver getDriver() {
        return driver;
    }

    public static void setUpDriver() {

        if (helperClass==null) {
            helperClass = new HelperClass();
        }
    }

    public static void tearDown() {

        if(driver!=null) {
            driver.quit();
        }

        helperClass = null;
    }

}

package com.example.definitions;

import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;

import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.testng.Assert;
import com.example.utils.HelperClass;

public class LoginPageDefinitions {

    LoginPageActions objLogin = new LoginPageActions();
    HomePageActions objHomePage = new HomePageActions();

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

        HelperClass.openPage(url);

    }

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

        // login to application
        objLogin.login(userName, passWord);

    }

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

        // Verify home page
        Assert.assertTrue(objHomePage.getHomePageText().contains("Dashboard"));

    }

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

        // Verify error message
        Assert.assertEquals(objLogin.getErrorMessage(),expectedErrorMessage);

    }

    @Then("User should be able to see a message {string} below Username")
    public void verifyMissingUsernameMessage(String message) {

        Assert.assertEquals(objLogin.getMissingUsernameText(),message);
    }

}

package com.example.definitions;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
import com.example.utils.HelperClass;

public class Hooks {

    @Before
    public static void setUp() {

        HelperClass.setUpDriver();
    }

    @After
    public static void tearDown(Scenario scenario) {

        //validate if scenario has failed
        if(scenario.isFailed()) {
            final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
            scenario.attach(screenshot, "image/png", scenario.getName());
        }

        HelperClass.tearDown();
    }
}

package com.example.runner;

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(features = "src/test/resources/features/LoginPage.feature",
        glue = "com.example.definitions",
        plugin = {
                "pretty",
                "com.aventstack.chaintest.plugins.ChainTestCucumberListener:"
        }
)
public class RunnerTests extends AbstractTestNGCucumberTests {
}

@CucumberOptions(plugin = { 
  "com.aventstack.chaintest.plugins.ChainTestCucumberListener:" 
})

# chaintest configuration
chaintest.project.name= ChaninTest Report with Cucumber and TestNG

# generators:
## chainlp
chaintest.generator.chainlp.enabled=true
chaintest.generator.chainlp.class-name=com.aventstack.chaintest.generator.ChainLPGenerator
chaintest.generator.chainlp.host.url=http://localhost/
chaintest.generator.chainlp.client.request-timeout-s=30
chaintest.generator.chainlp.client.expect-continue=false
chaintest.generator.chainlp.client.max-retries=3

## simple
chaintest.generator.simple.enabled=true
chaintest.generator.simple.document-title=chaintest
chaintest.generator.simple.class-name=com.aventstack.chaintest.generator.ChainTestSimpleGenerator
chaintest.generator.simple.output-file=target/chaintest/Index.html
chaintest.generator.simple.offline=false
chaintest.generator.simple.dark-theme=true
chaintest.generator.simple.datetime-format=yyyy-MM-dd hh:mm:ss a
chaintest.generator.simple.js=
chaintest.generator.simple.css=

## email
chaintest.generator.email.enabled=true
chaintest.generator.email.class-name=com.aventstack.chaintest.generator.ChainTestEmailGenerator
chaintest.generator.email.output-file=target/chaintest/Email.html
chaintest.generator.email.datetime-format=yyyy-MM-dd hh:mm:ss a

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
    <test  name="Cucumber with TestNG Test">
        <classes>
            <class name="com.example.runner.RunnerTests"/>
        </classes>
    </test> <!-- Test -->
</suite> <!-- Suite -->

This report contains the high level summary of the test execution.

mvn clean test

Replacement of Extent Report: ChainTest Report with Selenium and TestNG

HOME

<dependency>
  <groupId>com.aventstack</groupId>
  <artifactId>chaintest-testng</artifactId>
  <version>${chaintest.testng.version}</version>
</dependency>

<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>ChainTest_TestNG_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <selenium.version>4.28.1</selenium.version>
    <testng.version>7.10.2</testng.version>
    <chaintest.testng.version>1.0.7</chaintest.testng.version>
    <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <maven.surefire.plugin.version>3.2.5</maven.surefire.plugin.version>
    <aspectj.version>1.9.20.1</aspectj.version>
  </properties>

  <dependencies>

    <!-- 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>

    <!-- Chain Test Report -->
    <dependency>
      <groupId>com.aventstack</groupId>
      <artifactId>chaintest-testng</artifactId>
      <version>${chaintest.testng.version}</version>
    </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>

package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;

public class BasePage {
    public WebDriver driver;

    public BasePage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver,this);
    }

}

package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPage extends BasePage {

    public LoginPage(WebDriver driver) {
        super(driver);

    }

    @FindBy(name = "username")
    public WebElement userName;

    @FindBy(name = "password")
    public WebElement password;

    @FindBy(xpath = "//*[@type='submit']")
    public WebElement loginBtn;

    @FindBy(xpath = "//*[@id='flash']")
    public WebElement errorMessage;

    public void login(String strUserName, String strPassword) {
        userName.sendKeys(strUserName);
        password.sendKeys(strPassword);
        loginBtn.click();
    }

    public String getErrorMessage() {
        return errorMessage.getText();
    }

}
package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class SecurePage extends BasePage {

    public SecurePage(WebDriver driver) {
        super(driver);

    }

    @FindBy(xpath = "//*[@id='flash']")
    public WebElement securePageTitle;

    public String getSecurePageTitle() {
        return securePageTitle.getText();
    }

}

package com.example;

import com.aventstack.chaintest.plugins.ChainTestListener;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.testng.ITestResult;
import org.testng.annotations.*;

import java.time.Duration;

@Listeners(ChainTestListener.class)
public class BaseTests {

    public static WebDriver driver;
    public final static int TIMEOUT = 10;

    @BeforeTest
    @Parameters("browserName")
    public void setup(String browserName) throws Exception {

        System.out.println("Browser : " + browserName);
       
        switch (browserName.toLowerCase().trim()) {

            case "chrome":
                ChromeOptions options = new ChromeOptions();
                options.addArguments("--remote-allow-origins=*");
                options.addArguments("--no-sandbox");
                options.addArguments("--disable-dev-shm-usage");
                driver = new ChromeDriver(options);
                break;

            case "firefox":
                FirefoxOptions firefoxOptions = new FirefoxOptions();
                driver = new FirefoxDriver(firefoxOptions);
                break;
            case ("edge"):
                EdgeOptions edgeOptions = new EdgeOptions();
                driver = new EdgeDriver(edgeOptions);
                break;

            default:
                System.out.println("Incorrect browser is supplied...." + browserName);
                throw new IllegalArgumentException("Wrong Browser provided: " + browserName);
        }

        driver.manage().window().maximize();
        driver.get("https://the-internet.herokuapp.com/login");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
    }

   @AfterTest
   public void tearDown() {
       driver.quit();
   }

}

package com.example;

import org.testng.Assert;
import org.testng.annotations.Test;

public class LoginPageTests extends BaseTests {

    String actualLoginPageTitle;
    String actualErrorMessage;
    String actualDashboardPageTitle;

    @Test(priority = 0)
    public void verifyPageTitle() {

        actualLoginPageTitle = driver.getTitle();

        // Verify Page Title - Failed Test
       Assert.assertEquals(actualLoginPageTitle, "The Internet !!");
    }

    @Test(priority = 1)
    public void invalidCredentials() {

        LoginPage loginPage = new LoginPage(driver);
         loginPage.login("tomsmith", "happy!");
        actualErrorMessage = loginPage.getErrorMessage();

        // Verify Error Message
        Assert.assertTrue(actualErrorMessage.contains("Your password is invalid!"));
    }

    @Test(priority = 2)
    public void validLogin() {

        LoginPage loginPage = new LoginPage(driver);
        loginPage.login("tomsmith", "SuperSecretPassword!");

        SecurePage securePage = new SecurePage(driver);
        actualSecurePageTitle = securePage.getSecurePageTitle();

        // Verify Home Page
        Assert.assertTrue(actualSecurePageTitle.contains("You logged into a secure area!"));
    }
}

# chaintest configuration
chaintest.project.name= ChaninTest Report with Selenium and TestNG

# generators:
## chainlp
chaintest.generator.chainlp.enabled=true
chaintest.generator.chainlp.class-name=com.aventstack.chaintest.generator.ChainLPGenerator
chaintest.generator.chainlp.host.url=http://localhost/
chaintest.generator.chainlp.client.request-timeout-s=30
chaintest.generator.chainlp.client.expect-continue=false
chaintest.generator.chainlp.client.max-retries=3

## simple
chaintest.generator.simple.enabled=true
chaintest.generator.simple.document-title=chaintest
chaintest.generator.simple.class-name=com.aventstack.chaintest.generator.ChainTestSimpleGenerator
chaintest.generator.simple.output-file=target/chaintest/Index.html
chaintest.generator.simple.offline=false
chaintest.generator.simple.dark-theme=true
chaintest.generator.simple.datetime-format=yyyy-MM-dd hh:mm:ss a
chaintest.generator.simple.js=
chaintest.generator.simple.css=

## email
chaintest.generator.email.enabled=true
chaintest.generator.email.class-name=com.aventstack.chaintest.generator.ChainTestEmailGenerator
chaintest.generator.email.output-file=target/chaintest/Email.html
chaintest.generator.email.datetime-format=yyyy-MM-dd hh:mm:ss a

@Listeners(ChainTestListener.class)
public class BaseTests {
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="ChainTestReport with TestNG">

    <test name="Chrome Test">
        <parameter name="browserName" value="chrome" />
        <classes>
            <class name="com.example.LoginPageTests"/>
        </classes>
    </test> <!-- Test -->

    <test name="Firefox Test">
        <parameter name="browserName" value="firefox" />
        <classes>
            <class name="com.example.LoginPageTests"/>
        </classes>
    </test> <!-- Test -->

    <test name="Edge Test">
        <parameter name="browserName" value="edge" />
        <classes>
            <class name="com.example.LoginPageTests"/>
        </classes>
    </test> <!-- Test -->

</suite> <!-- Suite -->

This report contains the high level summary of the test execution.

mvn clean test

How to rerun failed tests twice in Cucumber

HOME

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(features = "src/test/resources/features/LoginPage.feature",
        glue = "com.example.definitions",
        plugin = {
                "pretty",
                "html:target/cucumber-reports/cucumber-report.html",
                "json:target/cucumber-reports/cucumber-report.json",
                "rerun:target/rerun.txt" // Saves paths of failed scenarios
        }
)
public class RunnerTests extends AbstractTestNGCucumberTests {
}

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(tags = "",
        features = "@target/rerun.txt",
        glue = "com.example.definitions",
        plugin =  {
                "pretty",
                "html:target/cucumber-reports/cucumber-rerun1-report.html",
                "json:target/cucumber-reports/cucumber-rerun1-report.json",
                "rerun:target/rerun1.txt"
        }
)

public class RunnerTestsFailed extends AbstractTestNGCucumberTests {
}

Create a third runner that reads from the rerun1.txt file and generates a separate JSON report for failed test reruns.

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(tags = "",
        features = "@target/rerun1.txt",
        glue = "com.example.definitions",
        plugin =  {
                "pretty",
                "html:target/cucumber-reports/cucumber-rerun2-report.html",
                "json:target/cucumber-reports/cucumber-rerun2-report.json"
        }
)

public class RunnerTestsSecondFailed extends AbstractTestNGCucumberTests {
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
    <test  name="Cucumber with TestNG Test">
        <classes>
            <class name="com.example.runner.RunnerTests"/>
            <class name="com.example.runner.RunnerTestsFailed"/>
            <class name="com.example.runner.RunnerTestsSecondFailed"/>
        </classes>
    </test> <!-- Test -->
</suite> <!-- Suite -->

<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>POM_Cucumber_TestNG_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.18.1</cucumber.version>
    <selenium.version>4.25.0</selenium.version>
    <testng.version>7.10.2</testng.version>
    <apache.common.version>2.4</apache.common.version>
    <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.3.1</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <maven.cucumber.reporting.version>5.8.2</maven.cucumber.reporting.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>

    <!-- Cucumber Reporting -->
    <dependency>
      <groupId>net.masterthought</groupId>
      <artifactId>cucumber-reporting</artifactId>
      <version>${maven.cucumber.reporting.version}</version>
    </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>
          <testFailureIgnore>true</testFailureIgnore>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
        </configuration>
      </plugin>

      <plugin>
        <groupId>net.masterthought</groupId>
        <artifactId>maven-cucumber-reporting</artifactId>
        <version>${maven.cucumber.reporting.version}</version>

        <executions>
          <execution>
            <id>generate-cucumber-report</id>
            <phase>verify</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <projectName>Cucumber Reporting Example</projectName>
              <outputDirectory>target/cucumber-html-reports</outputDirectory>
              <inputDirectory>target</inputDirectory>
              <jsonFiles>
                <!-- Include both main and rerun JSON reports -->
                <param>target/cucumber-reports/cucumber-report.json</param>
                <param>target/cucumber-reports/cucumber-rerun-report.json</param>
                <param>**/*.json</param>
              </jsonFiles>
            </configuration>
          </execution>
        </executions>
      </plugin>

    </plugins>
  </build>
</project>

mvn clean verify

How to create Cucumber Report after rerun of failed tests

Last Updated On

HOME

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(features = "src/test/resources/features/LoginPage.feature",
        glue = "com.example.definitions",
        plugin = {
                "pretty",
                "html:target/cucumber-reports/cucumber-report.html",
                "json:target/cucumber-reports/cucumber-report.json",
                "rerun:target/rerun.txt" // Saves paths of failed scenarios
        }
)
public class RunnerTests extends AbstractTestNGCucumberTests {
}

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(tags = "",
        features = "@target/rerun.txt",
        glue = "com.example.definitions",
        plugin =  {
                "pretty",
                "html:target/cucumber-reports/cucumber-rerun-report.html",
                "json:target/cucumber-reports/cucumber-rerun-report.json"
        }
)

public class RunnerTestsFailed extends AbstractTestNGCucumberTests {
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
    <test  name="Cucumber with TestNG Test">
        <classes>
            <class name="com.example.runner.RunnerTests"/>
            <class name="com.example.runner.RunnerTestsFailed"/>
        </classes>
    </test> <!-- Test -->
</suite> <!-- Suite -->

<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>POM_Cucumber_TestNG_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <cucumber.version>7.18.1</cucumber.version>
    <selenium.version>4.25.0</selenium.version>
    <testng.version>7.10.2</testng.version>
    <apache.common.version>2.4</apache.common.version>
    <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.3.1</maven.surefire.plugin.version>
    <maven.compiler.source.version>17</maven.compiler.source.version>
    <maven.compiler.target.version>17</maven.compiler.target.version>
    <maven.cucumber.reporting.version>5.8.2</maven.cucumber.reporting.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>

    <!-- Cucumber Reporting -->
    <dependency>
      <groupId>net.masterthought</groupId>
      <artifactId>cucumber-reporting</artifactId>
      <version>${maven.cucumber.reporting.version}</version>
    </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>
          <testFailureIgnore>true</testFailureIgnore>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
        </configuration>
      </plugin>

      <plugin>
        <groupId>net.masterthought</groupId>
        <artifactId>maven-cucumber-reporting</artifactId>
        <version>${maven.cucumber.reporting.version}</version>

        <executions>
          <execution>
            <id>generate-cucumber-report</id>
            <phase>verify</phase>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <projectName>Cucumber Reporting Example</projectName>
              <outputDirectory>target/cucumber-html-reports</outputDirectory>
              <inputDirectory>target</inputDirectory>
              <jsonFiles>
                <!-- Include both main and rerun JSON reports -->
                <param>target/cucumber-reports/cucumber-report.json</param>
                <param>target/cucumber-reports/cucumber-rerun-report.json</param>
                <param>**/*.json</param>
              </jsonFiles>
            </configuration>
          </execution>
        </executions>
      </plugin>

    </plugins>
  </build>
</project>

mvn clean verify

Fluent Wait in Serenity

HOME

In the previous tutorials, I explained the Implicit Wait in Serenity and Explicit Wait in Serenity. This tutorial will explain the Fluent Wait in Serenity.

What is Fluent Wait?

Fluent waits provide more flexibility, allowing us to specify polling intervals and ignore specific exceptions during the wait time.  Fluent Wait not only lets you specify the maximum amount of time to wait for a condition but also allows you to define the frequency with which the condition is checked and to ignore specific exceptions during the wait time.

Below is the example of Fluent wait.

import net.serenitybdd.annotations.DefaultUrl;
import net.serenitybdd.annotations.Managed;
import net.serenitybdd.core.annotations.findby.FindBy;
import net.serenitybdd.core.pages.PageObject;
import net.serenitybdd.core.pages.WebElementFacade;
import net.serenitybdd.junit.runners.SerenityRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.ElementNotInteractableException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.FluentWait;

import java.time.Duration;
import java.util.function.Function;

@RunWith(SerenityRunner.class)
@DefaultUrl("http://the-internet.herokuapp.com/dynamic_loading/1")
public class FluentWait_Demo extends PageObject {

    @Managed
    WebDriver driver;

    @FindBy(xpath = "//*[@id='start']/button")
    WebElementFacade startButton;


    @FindBy(xpath = "//*[@id='finish']/h4")
    WebElementFacade pageText;

    @Test
    public void fluentWaitDemo() throws InterruptedException {

        open();
        startButton.click();
        waitForElementWithFluentWait(pageText);

    }

    public void waitForElementWithFluentWait(WebElement pageText) {
        FluentWait wait = new FluentWait<>(getDriver())
                .withTimeout(Duration.ofSeconds(10))
                .pollingEvery(Duration.ofSeconds(2))
                .ignoring(ElementNotInteractableException.class);

        wait.until((Function<WebDriver, Boolean>)
                driver -> pageText.isDisplayed());

        System.out.println("Text :" + pageText.getText());
        System.out.println("Fluent Time defined for the test (in seconds) :" + getWaitForTimeout().toSeconds());
    }
}

public void waitForElementWithFluentWait(WebElement pageText) {
        FluentWait wait = new FluentWait<>(getDriver())
                .withTimeout(Duration.ofSeconds(10))
                .pollingEvery(Duration.ofSeconds(2))
                .ignoring(ElementNotInteractableException.class);

       wait.until(driver -> pageText.isDisplayed());

        System.out.println("Text :" + pageText.getText());
        System.out.println("Fluent Time defined for the test (in seconds) :" + getWaitForTimeout().toSeconds());
    }

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