Integrate Allure Report with Playwright with Java, Cucumber, and JUnit5

Last Updated On

HOME

In this tutorial, I will explain how to Integrate Allure Report 3 with Playwright, Java Cucumber,  and JUnit5.

Before starting, make sure to install Allure on your machine. Refer to this tutorial to install allure – What is Allure Report?.

Table of Contents

System requirements

  1. Java 17 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed
  4. Allure installed
  5. Browsers on which tests need to be run, like Chrome, Firefox, etc.

Dependency List

  1. Playwright – 1.57.0
  2. Java 17
  3. Cucumber – 7.33.0
  4. Maven – 3.9.6
  5. Allure Report – 2.32.0
  6. Allure Maven – 2.12.0
  7. Aspectj – 1.9.25.1
  8. Maven Compiler Plugin – 3.13.1
  9. Maven Surefire Plugin – 3.5.4

Implementation Steps

Step 1 – Update the Properties section in Maven pom.xml
<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>17</java.version>
        <cucumber.version>7.33.0</cucumber.version>
        <playwright.version>1.57.0</playwright.version>
        <lombok.version>1.18.30</lombok.version>
        <junit.platform.version>6.1.0-M1</junit.platform.version>
        <junit.jupiter.api.version>6.1.0-M1</junit.jupiter.api.version>
        <junit.jupiter.params.version>6.1.0-M1</junit.jupiter.params.version>
        <junit.platform.launcher.version>6.1.0-M1</junit.platform.launcher.version>
        <maven.compiler.plugin.version>3.14.1</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.5.4</maven.surefire.plugin.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25.1</aspectj.version>
</properties>

Step 2 – Add dependencies to pom.xml

Add Cucumber, JUnit Platform, Allure-Cucumber, and Allure-JUnit-Platform dependencies to pom.xml (Maven Project).

 <!-- 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>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>${playwright.version}</version>
        </dependency>

        <!-- JUnit 5 -->
        <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>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>${junit.platform.launcher.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Cucumber with Java -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Cucumber with Junit5 -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit-platform-engine</artifactId>
            <version>${cucumber.version}</version>
        </dependency>

        <!-- JUnit Platform -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>${junit.platform.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-cucumber7-jvm</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit-platform</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>
                    <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>
                    </dependency>
                </dependencies>
            </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>Cucumber_Playwright_JUnit5</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>17</java.version>
        <cucumber.version>7.33.0</cucumber.version>
        <playwright.version>1.57.0</playwright.version>
        <lombok.version>1.18.30</lombok.version>
        <junit.platform.version>6.1.0-M1</junit.platform.version>
        <junit.jupiter.api.version>6.1.0-M1</junit.jupiter.api.version>
        <junit.jupiter.params.version>6.1.0-M1</junit.jupiter.params.version>
        <junit.platform.launcher.version>6.1.0-M1</junit.platform.launcher.version>
        <maven.compiler.plugin.version>3.14.1</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.5.4</maven.surefire.plugin.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25.1</aspectj.version>
    </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>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>${playwright.version}</version>
        </dependency>

        <!-- JUnit 5 -->
        <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>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <version>${junit.platform.launcher.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Cucumber with Java -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Cucumber with Junit5 -->
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit-platform-engine</artifactId>
            <version>${cucumber.version}</version>
        </dependency>

        <!-- JUnit Platform -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>${junit.platform.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-cucumber7-jvm</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit-platform</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>
                    <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>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

2. 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.

@allure.label.parent_suite:WebInterface
@allure.label.sub_suite:Login Page
@allure.label.owner:Vibha

Feature: Login to HRM Application

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

  @ValidCredentials @Critical
  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 opens with heading "Dashboard"

  @InvalidCredentials @High
  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 @Medium
  Scenario: Login with blank username

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

7. Create the step definition class in src/test/java

8. Create a JUnit Cucumber Runner class

This JUnit 5 runner configures and launches Cucumber scenarios by selecting feature files, defining glue code packages, and executing them via the Cucumber engine on the JUnit Platform.

import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;

import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(
        key = GLUE_PROPERTY_NAME,
        value = "com.example"
)


public class RunnerTests {
}

cucumber.publish.enabled=true
cucumber.plugin=io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm
#allure.properties
allure.results.directory=build/allure-results

11. Run the Test and Generate Allure Report

To run the tests, use the below command

mvn clean test

In the image below, 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 build folder. These files will be used to generate Allure Report.

12. How to Generate a Report

Use the command below to generate the Allure Report

 allure serve build/allure-results

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

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.

 allure awesome build/allure-results

Congratulations!! We have integrated an allure report with Playwright, Java Cucumber, 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

Integrate Allure Report with Playwright with Java, Cucumber, and TestNG

Last Updated On

HOME

In this tutorial, I will explain how to Integrate Allure Report 3 with Playwright, Java Cucumber,  and TestNG.

Before starting, make sure to install Allure on your machine. Refer to this tutorial to install allure – What is Allure Report?.

Table of Contents

System requirements

  1. Java 17 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed
  4. Allure installed
  5. Browsers on which tests need to be run, like Chrome, Firefox, etc.

Dependency List

  1. Playwright – 1.57.0
  2. Java 17
  3. Cucumber – 7.33.0
  4. Maven – 3.9.6
  5. TestNG – 7.11.0
  6. Allure Report – 2.32.0
  7. Aspectj – 1.9.25.1
  8. Maven Compiler Plugin – 3.13.0
  9. Maven Surefire Plugin – 3.5.4

Implementation Steps

Step 1 – Update the Properties section in Maven pom.xml
 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <testng.version>7.11.0</testng.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25</aspectj.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.5.4</maven.surefire.plugin.version>
</properties>

Step 2 – Add dependencies to pom.xml

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

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

    <!-- Cucumber with Java -->
    <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-java</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>

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

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

    <!-- Playwright -->
    <dependency>
      <groupId>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>${playwright.version}</version>
    </dependency>

    <!-- Add necessary Allure dependencies -->
      <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-cucumber7-jvm</artifactId>
        <scope>test</scope>
      </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>Playwright_PageObjectModel</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <testng.version>7.11.0</testng.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25</aspectj.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.5.4</maven.surefire.plugin.version>
    </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>

        <!-- Playwright -->
        <dependency>
            <groupId>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>${playwright.version}</version>
        </dependency>

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

        <!-- Allure-TestNG -->
        <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>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>


2. 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.

@allure.label.parent_suite:WebInterface
@allure.label.sub_suite:Login Page
@allure.label.owner:Vibha

Feature: Login to HRM Application

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

  @ValidCredentials @Critical
  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 opens with heading "Dashboard"

  @InvalidCredentials @High
  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 @Medium
  Scenario: Login with blank username

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

7. Create the step definition class in src/test/java

8. 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 io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

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

public class RunnerTests 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.

9. 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>

#allure.properties
allure.results.directory=build/allure-results

11. Run the Test and Generate Allure Report

To run the tests, use the below command

mvn clean test

In the image below, 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 build folder. These files will be used to generate Allure Report.

12. How to Generate a Report

Use the command below to generate the Allure Report

 allure serve build/allure-results

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

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.

 allure awesome build/allure-results

Congratulations!! We have integrated an allure report with Playwright, Java Cucumber, 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

Integrate Allure Report with Playwright with Java and JUnit5

Last Updated On

HOME

In this tutorial, I will explain how to Integrate Allure Report 3 with Playwright, Java and JUnit5.

Refer to this tutorial to install allure – What is Allure Report?.

Table of Contents

System requirements

  1. Java 17 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed
  4. Allure installed
  5. Browsers on which tests need to be run, like Chrome, Firefox, etc.

Dependency List

  1. Playwright – 1.57.0
  2. Java 17
  3. Maven – 3.9.6
  4. Allure Report – 2.32.0
  5. Aspectj – 1.9.25
  6. Maven Compiler Plugin – 3.13.0
  7. Maven Surefire Plugin – 3.5.4

Implementation Steps

Step 1 – Update the Properties section in Maven pom.xml
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <playwright.version>1.57.0</playwright.version>
    <junit.jupiter.engine.version>6.1.0-M1</junit.jupiter.engine.version>
    <junit.jupiter.api.version>6.1.0-M1</junit.jupiter.api.version>
    <junit.jupiter.params.version>6.1.0-M1</junit.jupiter.params.version>
    <junit.platform.launcher.version>6.1.0-M1</junit.platform.launcher.version>
    <maven.compiler.plugin.version>3.14.1</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.5.4</maven.surefire.plugin.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <maven.site.plugin.version>4.0.0-M16</maven.site.plugin.version>
    <allure.version>2.32.0</allure.version>
    <aspectj.version>1.9.25.1</aspectj.version>
  </properties>

Step 2 – Add dependencies to pom.xml

Add Playwright, JUnit Jupiter Engine, JUnit Jupiter API, JUnit Param, JUnit Platform and Allure-JUnit5 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>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>${playwright.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>org.junit.platform</groupId>
      <artifactId>junit-platform-launcher</artifactId>
      <version>${junit.platform.launcher.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>io.qameta.allure</groupId>
      <artifactId>allure-junit5</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>
          <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>
          </dependency>
        </dependencies>
      </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>PageObjectModel_Playwright_JUnit5</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <playwright.version>1.57.0</playwright.version>
    <junit.jupiter.engine.version>6.1.0-M1</junit.jupiter.engine.version>
    <junit.jupiter.api.version>6.1.0-M1</junit.jupiter.api.version>
    <junit.jupiter.params.version>6.1.0-M1</junit.jupiter.params.version>
    <junit.platform.launcher.version>6.1.0-M1</junit.platform.launcher.version>
    <maven.compiler.plugin.version>3.14.1</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.5.4</maven.surefire.plugin.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <maven.site.plugin.version>4.0.0-M16</maven.site.plugin.version>
    <allure.version>2.32.0</allure.version>
    <aspectj.version>1.9.25.1</aspectj.version>
  </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>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>${playwright.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>org.junit.platform</groupId>
      <artifactId>junit-platform-launcher</artifactId>
      <version>${junit.platform.launcher.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>io.qameta.allure</groupId>
      <artifactId>allure-junit5</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>
          <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>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

</project>


2. Project Structure for Maintainability

Creating a well-organized project structure is crucial for maintaining a scalable and efficient automation framework.

3. Creating Page Object Classes in src/test/java

package com.example.pages;

import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import io.qameta.allure.Step;

public class LoginPage {

    private final Page page;

    // Locators
    private final Locator usernameLocator;
    private final Locator passwordLocator;
    private final Locator submitLocator;
    private final Locator invalidCredentialsLocator;
    private final Locator missingUsernameErrorMessageLocator;

    public LoginPage(Page page) {
        this.page = page;
        this.usernameLocator = page.locator("input[name='username']");
        this.passwordLocator = page.locator("input[name='password']");
        this.submitLocator = page.locator("button[type='submit']");
        this.invalidCredentialsLocator = page.locator("//p[contains(@class, \"oxd-text oxd-text--p oxd-alert-content-text\")]");
        this.missingUsernameErrorMessageLocator = page.locator("//span[contains(@class, 'oxd-text oxd-text--span oxd-input-field-error-message oxd-input-group__message')]");
    }

    @Step("Enter credentials")
    public void login(String user, String pass){
        usernameLocator.fill(user);
        passwordLocator.fill(pass);
        submitLocator.click();
    }

    @Step("Get Error Message for invalid credentials")
    public String getErrorMessage () {
        return invalidCredentialsLocator.textContent();
    }

    @Step("Get Error Message for missing username")
    public String getMissingUsernameErrorMessage () {
        return missingUsernameErrorMessageLocator.textContent();
    }
}

package com.example.pages;

import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import io.qameta.allure.Step;

public class DashboardPage {

    private Page page;

    private final Locator headingLocator;

    public DashboardPage(Page page){
        this.page = page;
        this.headingLocator = page.locator("//h6[contains(@class, \"oxd-topbar-header-breadcrumb-module\")]");
        this.assignLeaveLocator = page.locator("//[contains(@text, \"Assign Leave\")]");
        this.leaveListLocator = page.getByTitle("Leave List");

    }

    @Step("Get Heading of Dashboard page")
    public String getDashboardPageHeading() {
        return headingLocator.textContent();
    }

}

package com.example.utils;

import com.microsoft.playwright.*;
import org.junit.jupiter.api.*;

// Subclasses will inherit PER_CLASS behavior.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTests {

    // Shared between all tests in the class.
    static Playwright playwright;
    static Browser browser;

    // New instance for each test method.
    BrowserContext context;
    protected Page page;

    @BeforeAll
    public static void launchBrowser() {
        playwright = Playwright.create();
        browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));

    }

    @AfterAll
    public static void closeBrowser() {
        playwright.close();
    }


    @BeforeEach
    public void createContextAndPage() {
        context = browser.newContext();
        page = context.newPage();
        page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    }

    @AfterEach
    public void closeContext() {
        context.close();
    }
}

package com.example.tests;

import com.example.pages.DashboardPage;
import com.example.pages.LoginPage;
import com.example.utils.BaseTests;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import io.qameta.allure.Description;
import io.qameta.allure.Issue;
import io.qameta.allure.Link;
import io.qameta.allure.Owner;
import io.qameta.allure.Severity;
import io.qameta.allure.TmsLink;
import org.junit.jupiter.api.DisplayName;

import static io.qameta.allure.SeverityLevel.CRITICAL;

public class LoginTests extends BaseTests {

    @ParameterizedTest
    @CsvFileSource(files = "src/test/resources/testData/credentials.csv", numLinesToSkip = 1)
    @DisplayName("Login Authentication")
    @Description("This test attempts to log into the website using a incorrect username and a password. Fails if any error happens.")
    @Severity(CRITICAL)
    @Owner("Vibha Singh")
    @Link(name = "Website", url = "https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
    @Issue("AUTH-123")
    @TmsLink("TMS-456")
    public void unsuccessfulLogin(String username, String password, String expectedErrorMessage) {

        LoginPage loginPage = new LoginPage(page);
        loginPage.login(username,password);
        String actualErrorMessage = loginPage.getErrorMessage();
        Assertions.assertEquals(expectedErrorMessage, actualErrorMessage, "Incorrect error message is displayed");

   }

    @Test
    @DisplayName("Successful Login Authentication")
    @Description("This test attempts to log into the website using a correct username and a password. Fails if any error happens.")
    @Severity(CRITICAL)
    @Owner("Vibha Singh")
    @Link(name = "Website", url = "https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
    @Issue("AUTH-124")
    @TmsLink("TMS-460")
    public void successfulLogin() {

        LoginPage loginPage = new LoginPage(page);
        loginPage.login("Admin","admin123");
        DashboardPage dashboardPage = new DashboardPage(page);
        String actualHeading = dashboardPage.getDashboardPageHeading();
        Assertions.assertEquals("Dashboard",actualHeading, "Unable to login to the application");

    }

}
@Description("This test attempts to log into the website using a invalid login and a password that result in error")

#allure.properties
allure.results.directory=target/allure-results

7. Run the Tests and Generate Allure Report

To run the tests, use the below command

mvn clean test

The output of the above program is

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

8. How to Generate an Allure Report

Use the command below to generate the Allure Report

 allure serve build/allure-results

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

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. Here on this tab, they are arranged according to their sequential or parallel timing structure.

 allure awesome build/allure-results

This will create the allure-report folder with all the test files and index.html report.

Congratulations!! We have integrated an allure report with Playwright, Java, and JUnit5. 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

Integrate Allure Report with Playwright with Java and TestNG

Last Updated On

HOME

In this tutorial, I will explain how to Integrate Allure Report 3 with Playwright, Java and TestNG.

Refer to this tutorial to install allure – What is Allure Report?.

Table of Contents

System requirements

  1. Java 17 installed
  2. Maven installed
  3. Eclipse or IntelliJ installed
  4. Allure installed
  5. Browsers on which tests need to be run, like Chrome, Firefox, etc.

Dependency List

  1. Playwright – 1.57.0
  2. Java 17
  3. Maven – 3.9.6
  4. Allure Report – 2.32.0
  5. Aspectj – 1.9.25
  6. Maven Compiler Plugin – 3.13.0
  7. Maven Surefire Plugin – 3.5.4

High-Level Execution Flow

Implementation Steps

Step 1 – Update the Properties section in Maven pom.xml
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <playwright.version>1.57.0</playwright.version>
    <testng.version>7.11.0</testng.version>
    <allure.version>2.32.0</allure.version>
    <aspectj.version>1.9.25</aspectj.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.5.4</maven.surefire.plugin.version>
  </properties>

Step 2 – Add dependencies to pom.xml

Add Playwright, TestNG, 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>

        <!-- Playwright -->
        <dependency>
            <groupId>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>${playwright.version}</version>
        </dependency>

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

        <!-- Allure-TestNG -->
        <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>
                    </dependency>
                </dependencies>
            </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>Playwright_PageObjectModel</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <testng.version>7.11.0</testng.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25</aspectj.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.5.4</maven.surefire.plugin.version>
    </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>

        <!-- Playwright -->
        <dependency>
            <groupId>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
            <version>${playwright.version}</version>
        </dependency>

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

        <!-- Allure-TestNG -->
        <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>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>


2. Project Structure for Maintainability

Creating a well-organized project structure is crucial for maintaining a scalable and efficient automation framework.

3. Creating Page Object Classes in src/test/java

package com.example.utils;

import io.qameta.allure.Attachment;

public abstract class AllureAttachments {

    @Attachment(value = "Failure Screenshot", type = "image/png")
    public static byte[] attachScreenshot(byte[] screenshot) {
        return screenshot;
    }
}

package com.example.utils;

import com.microsoft.playwright.*;
import org.testng.annotations.*;

public class BaseClass {

    // Shared between all tests in this class.
    Playwright playwright;
    Browser browser = null;

    // New instance for each test method.
    BrowserContext context;
    public Page page;

    public Page getPage() {
        return page;
    }

    @BeforeClass
    public void launchBrowser() {
        playwright = Playwright.create();
        browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
    }

    @BeforeMethod
    public void createContextAndPage() {
        context = browser.newContext();
        page = context.newPage();
        page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    }

    @AfterMethod
    public void closeContext() {
        context.close();
    }

    @AfterClass
    public void closeBrowser() {
        playwright.close();
    }
}

package com.example.utils;

import com.microsoft.playwright.Page;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class TestListener implements ITestListener {

     @Override
    public void onTestFailure(ITestResult result) {
        System.out.println("❌ onTestFailure triggered");
        Page page = BaseClass.getPage();
        if (page != null) {
            byte[] screenshot = page.screenshot();
            AllureAttachments.attachScreenshot(screenshot);
        }
    }
}

package com.example.tests;

import com.example.pages.DashboardPage;
import com.example.pages.LoginPage;
import com.example.utils.BaseClass;
import com.example.utils.TestListener;
import io.qameta.allure.Description;
import io.qameta.allure.Owner;
import io.qameta.allure.Severity;
import org.testng.Assert;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import static io.qameta.allure.SeverityLevel.*;

public class LoginTests extends BaseClass {

    @Test
    @Description("This test attempts to log into the website using a invalid login and a password that result in error")
    @Severity(NORMAL)
    @Owner("Vibha Singh")
    public void unsuccessfulLogin() {
        LoginPage loginPage = new LoginPage(page);
        loginPage.login("abc","abc");
        String actualErrorMessage = loginPage.getErrorMessage();
        Assert.assertEquals(actualErrorMessage, "Invalid credentials");
   }

    @Test
    @Description("This test attempts to log into the website using a valid login and a password")
    @Severity(CRITICAL)
    @Owner("Vibha Singh")
    public void successfulLogin() {
        LoginPage loginPage = new LoginPage(page);
        loginPage.login("Admin","admin123");
        DashboardPage dashboardPage = new DashboardPage(page);
        String actualHeading = dashboardPage.getDashboardPageHeading();
        Assert.assertEquals(actualHeading, "Dashboard");
    }

    @Test
    @Description("This test attempts to log into the website using a blank login and a password that result in error")
    @Severity(MINOR)
    @Owner("Vibha Singh")
    public void missingUsername() {
        LoginPage loginPage = new LoginPage(page);
        loginPage.login("","admin123");
        String actualErrorMessage = loginPage.getMissingUsernameErrorMessage();
        Assert.assertEquals(actualErrorMessage, "Required1");
    }

}

@Description("This test attempts to log into the website using a invalid login and a password that result in error")

6. 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="Playwright test suite">

    <listeners>
        <listener class-name="com.example.utils.TestListener"/>
    </listeners>

    <test name="Integration of Playwright Java with TestNG">
    <classes>
        <class name="com.example.tests.LoginTests">

        </class>
    </classes>
    </test>
</suite>

#allure.properties
allure.results.directory=target/allure-results

8. Run the Tests and Generate Allure Report

To run the tests, use the below command

mvn clean test

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

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

9. How to Generate an Allure Report

Use the command below to generate the Allure Report

 allure serve build/allure-results

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

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. Here on this tab, they are arranged according to their sequential or parallel timing structure.

 allure awesome build/allure-results

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

Integration of Playwright Java with TestNG

HOME

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

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

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <playwright.version>1.57.0</playwright.version>
    <testng.version>7.11.0</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.5.4</maven.surefire.plugin.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>${playwright.version}</version>
    </dependency>

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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Playwright test suite">
    <test name="Integration of Playwright Java with TestNG">
    <classes>
        <class name="com.example.TestNG_Demo_Tests">
        </class>
    </classes>
    </test>
</suite>

package com.example;

import com.microsoft.playwright.*;
import org.testng.annotations.*;

import static org.testng.Assert.assertEquals;


public class TestNG_Demo_Tests {

    // Shared between all tests in this class.
    Playwright playwright;
    Browser browser;

    // New instance for each test method.
    BrowserContext context;
    Page page;

    @BeforeClass
    void launchBrowser() {
        playwright = Playwright.create();
        browser = playwright.chromium().launch();
    }

    @BeforeMethod
    void createContextAndPage() {
        context = browser.newContext();
        page = context.newPage();
        page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    }

    @Test
    void verifyPageTitle() {
        System.out.println("Page Title :" + page.title());
        assertEquals("OrangeHRM", page.title());
    }

    @Test
    void verifyLogin() {
        page.locator("input[name='username']").fill("Admin");
        page.locator("input[name='password']").fill("admin123");
        page.locator("button[type='submit']").click();
        String expectedValue = page.locator("//h6[contains(@class, \"oxd-topbar-header-breadcrumb-module\")]").textContent();
        assertEquals(expectedValue,"Dashboard");
    }

    @Test
    void verifyInvalidCredentials() {
        page.locator("input[name='username']").fill("Playwright");
        page.locator("input[name='password']").fill("admin123");
        page.locator("button[type='submit']").click();
        String expectedValue = page.locator("//p[contains(@class, \"oxd-text oxd-text--p oxd-alert-content-text\")]").textContent();
        assertEquals(expectedValue,"Invalid credentials");
    }

    @AfterMethod
    void closeContext() {
        context.close();
    }

    @AfterClass
    void closeBrowser() {
        playwright.close();
    }
}
Playwright playwright;
Browser browser = null;
BrowserContext context;
Page page;

This method is annotated with @BeforeClass, indicating it runs once before any test methods in the current class.

The browser is launched in Chromium and non-headless mode (setHeadless(false)), meaning an actual browser window is opened.

@BeforeMethod
void createContextAndPage() {
      context = browser.newContext();
      page = context.newPage();
      page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
}
@AfterMethod
   void closeContext() {
       context.close();
}
@AfterClass
void closeBrowser() {
      playwright.close();
}

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