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

Parameterized Tests in Playwright Java using JUnit5

HOME

@ParameterizedTest
    @CsvSource({
            "admin123,admin123,Invalid credentials",
            "admin,admin12,Invalid credentials",
            "Admin,1234,Invalid credentials",
            "12345,%^$£56,Invalid credentials"
    })
    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, "");

   }

<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>
    <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>
    <maven.surefire.report.plugin.version>3.5.4</maven.surefire.report.plugin.version>
  </properties>

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

  </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>
        </configuration>
      </plugin>

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

  <reporting>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-report-plugin</artifactId>
        <version>${maven.surefire.report.plugin.version}</version>
        <configuration>
          <outputName>JUnit5 Report</outputName>
        </configuration>
      </plugin>
    </plugins>
  </reporting>

</project>

import com.microsoft.playwright.Page;

public class LoginPage {

    private Page page;

    //Locators
    private final String usernameLocator = "input[name='username']";
    private final String passwordLocator = "input[name='password']";
    private final String submitButton = "button[type='submit']";
    private final String errorMessage = "//p[contains(@class, 'oxd-text oxd-text--p oxd-alert-content-text')]";

    //Constructor
    public LoginPage(Page page){
        this.page = page;
    }

    public void login(String username, String password) {
        page.fill(usernameLocator,username);
        page.fill(passwordLocator,password);
        page.click(submitButton);
    }

    public String getErrorMessage(){
        return page.textContent(errorMessage);
    }
}

package org.example.pages;

import com.microsoft.playwright.Page;

public class DashboardPage {

    private Page page;

    //Locators
    private final String dashboardHeading = "//h6[contains(@class, 'oxd-topbar-header-breadcrumb-module')]";

    //Constructor
    public DashboardPage(Page page) {
        this.page = page;
    }

    // Methods
    public String getHeading() {
        return page.textContent(dashboardHeading);
    }
}

package org.example.utils;
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();
    }
}
Playwright playwright;
Browser browser = null;
BrowserContext context;
Page page;
  @BeforeAll
    public void launchBrowser() {
        playwright = Playwright.create();
        browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
    }

@BeforeMethod
void createContextAndPage() {
      context = browser.newContext();
      page = context.newPage();
      page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
}
@AfterAll
 public static void closeBrowser() {
        playwright.close();
 }
@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;

public class LoginTests extends BaseTests {

    @ParameterizedTest
    @CsvSource({
            "admin123,admin123,Invalid credentials",
            "admin,admin12,Invalid credentials",
            "Admin,1234,Invalid credentials",
            "12345,%^$£56,Invalid credentials"
    })
    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, "");

   }

    @Test
    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");

    }

}
@ParameterizedTest
    @CsvSource({
            "admin123,admin123,Invalid credentials",
            "admin,admin12,Invalid credentials",
            "Admin,1234,Invalid credentials",
            "12345,%^$£56,Invalid credentials"
    })

mvn clean test site

    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

    Integration of Playwright with Java, Cucumber and JUnit5

    HOME

    Benefits of Using Cucumber with Playwright

    <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.jupiter.engine.version>6.1.0-M1</junit.jupiter.engine.version>
            <junit.jupiter.version>6.1.0-M1</junit.jupiter.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>
            <maven.surefire.report.plugin.version>3.5.4</maven.surefire.report.plugin.version>
            <cucumber.junit.platform.engine>7.14.0</cucumber.junit.platform.engine>
        </properties>
    
        <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.version}</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-params</artifactId>
                <version>${junit.jupiter.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.junit.platform.engine}</version>
            </dependency>
    
            <!-- JUnit Platform -->
            <dependency>
                <groupId>org.junit.platform</groupId>
                <artifactId>junit-platform-suite</artifactId>
                <version>${junit.jupiter.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>
                        <testFailureIgnore>true</testFailureIgnore>
                    </configuration>
                </plugin>
    
            </plugins>
        </build>
    
    <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-site-plugin</artifactId>
            <version>${maven.site.plugin.version}</version>
    </plugin>
    
    <reporting>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-report-plugin</artifactId>
                    <version>${maven.surefire.report.plugin.version}</version>
                    <configuration>
                        <outputName>JUnit5 Report</outputName>
                    </configuration>
                </plugin>
            </plugins>
        </reporting>
    

    <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.jupiter.engine.version>6.1.0-M1</junit.jupiter.engine.version>
            <junit.jupiter.version>6.1.0-M1</junit.jupiter.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>
            <maven.surefire.report.plugin.version>3.5.4</maven.surefire.report.plugin.version>
            <cucumber.junit.platform.engine>7.14.0</cucumber.junit.platform.engine>
        </properties>
    
        <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.version}</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-params</artifactId>
                <version>${junit.jupiter.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.junit.platform.engine}</version>
            </dependency>
    
            <!-- JUnit Platform -->
            <dependency>
                <groupId>org.junit.platform</groupId>
                <artifactId>junit-platform-suite</artifactId>
                <version>${junit.jupiter.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>
                        <testFailureIgnore>true</testFailureIgnore>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>${maven.site.plugin.version}</version>
                </plugin>
            </plugins>
        </build>
    
        <reporting>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-report-plugin</artifactId>
                    <version>${maven.surefire.report.plugin.version}</version>
                    <configuration>
                        <outputName>JUnit5 Report</outputName>
                    </configuration>
                </plugin>
            </plugins>
        </reporting>
    </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 opens with heading "Dashboard"
    
      @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
    
        When User enters username as " " and password as "admin123"
        Then User should be able to see a message "Required" below Username
    

    package com.example.utils;
    
    import com.microsoft.playwright.*;
    
    public class PlaywrightFactory {
    
        private static Playwright playwright;
        private static Browser browser;
        private static BrowserContext context;
        private static Page page;
    
        public static void initBrowser() {
    
            playwright = Playwright.create();
            browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
            context = browser.newContext();
            page = context.newPage();
        }
    
        public static Page getPage() {
            return page;
        }
    
        public static void closeBrowser() {
            if (page != null) page.close();
            if (context != null) context.close();
            if (browser != null) browser.close();
            if (playwright != null) playwright.close();
        }
    }
    
    

    package com.example.hooks;
    
    import com.example.utils.PlaywrightFactory;
    import com.microsoft.playwright.*;
    import io.cucumber.java.After;
    import io.cucumber.java.Before;
    import io.cucumber.java.Scenario;
    
    public class Hooks {
    
        @Before
        public void beforeScenario(Scenario scenario) {
            System.out.println("Starting scenario: " + scenario.getName());
            PlaywrightFactory.initBrowser();
        }
    
        @After
        public void afterScenario(Scenario scenario) {
            Page page = PlaywrightFactory.getPage();
            if (page != null && scenario.isFailed()) {
                scenario.attach(page.screenshot(), "image/png", scenario.getName());
            }
            PlaywrightFactory.closeBrowser();  
            System.out.println("Finished scenario: " + scenario.getName());
        }
    }
    
    
    
    package com.example.pages;
    
    import com.microsoft.playwright.*;
    
    public class LoginPage {
    
        private Page page;
    
        // Locators
        private final Locator usernameLocator;
        private final Locator passwordLocator;
        private final Locator submitLocator;
        private final Locator invalidCredentialsLocator;
        private final Locator missingUsernameLocator;
    
        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.missingUsernameLocator = page.locator("//span[contains(@class, 'oxd-text oxd-text--span oxd-input-field-error-message oxd-input-group__message')]");
        }
    
        public void login(String user, String pass){
            usernameLocator.fill(user);
            passwordLocator.fill(pass);
            submitLocator.click();
        }
    
        public void getUrl(String url){
            page.navigate(url);
        }
    
        public String getMissingUsernameErrorMessage() {
            return missingUsernameLocator.textContent();
        }
    
        public String getErrorMessage () {
            return invalidCredentialsLocator.textContent();
        }
    }
    
    
    package com.example.pages;
    
    import com.microsoft.playwright.Locator;
    import com.microsoft.playwright.Page;
    
    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")]");
        }
    
        public String getDashboardPageHeading() {
            return headingLocator.textContent();
        }
    
    }
    
    
    package com.example.steps;
    
    import com.example.utils.PlaywrightFactory;
    import com.microsoft.playwright.Page;
    
    public class BaseStep {
    
        protected Page getPage() {
            Page page = PlaywrightFactory.getPage();
            if (page == null) {
                throw new RuntimeException(
                        "Page is NULL. Ensure @Before hook ran and glue includes hooks package."
                );
            }
            return page;
        }
    }
    
    

    package com.example.definitions;
    
    import com.example.pages.DashboardPage;
    import com.example.pages.LoginPage;
    import com.example.steps.BaseStep;
    import io.cucumber.java.en.Given;
    import io.cucumber.java.en.Then;
    import io.cucumber.java.en.When;
    import org.junit.jupiter.api.Assertions;
    
    
    public class LoginPageDefinitions extends BaseStep {
    
        private LoginPage loginPage;
        private DashboardPage dashboardPage;
    
        @Given("User is on HRMLogin page {string}")
        public void userIsOnHRMLoginPage(String baseUrl) {
            loginPage = new LoginPage(getPage());
            loginPage.getUrl(baseUrl);
        }
    
        @When("User enters username as {string} and password as {string}")
        public void userEntersUsernameAsAndPasswordAs(String username, String password) {
            loginPage.login(username, password);
        }
    
        @Then("User should be able to see error message {string}")
        public void userShouldBeAbleToSeeErrorMessage(String expectedErrorMessage) {
            Assertions.assertEquals(expectedErrorMessage, loginPage.getErrorMessage());
        }
    
        @Then("User should be able to see a message {string} below Username")
        public void userShouldBeAbleToSeeAMessageBelowUsername(String expectedErrorMessage) {
            Assertions.assertEquals(expectedErrorMessage, loginPage.getMissingUsernameErrorMessage());
        }
    
        @Then("User should be able to login successfully and new page opens with heading {string}")
        public void userShouldBeAbleToLoginSuccessfullyAndNewPageOpen(String expectedHeading) {
            dashboardPage = new DashboardPage(getPage());
            Assertions.assertEquals(expectedHeading, dashboardPage.getDashboardPageHeading());
    
        }
    
    }
    

    package com.example.runner;
    
    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 {
    }
    
    
    mvn clean site test
    

    cucumber.publish.enabled=true
    

    • Hooks: Hooks manage browser setup, teardown, and failure handling

    Setting Up Page Object Model with Playwright and JUnit5

    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>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>
        <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>
        <maven.surefire.report.plugin.version>3.5.4</maven.surefire.report.plugin.version>
      </properties>
    
      <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>
    
      </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>
            </configuration>
          </plugin>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-site-plugin</artifactId>
            <version>${maven.site.plugin.version}</version>
          </plugin>
        </plugins>
      </build>
    
      <reporting>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-report-plugin</artifactId>
            <version>${maven.surefire.report.plugin.version}</version>
            <configuration>
              <outputName>JUnit5 Report</outputName>
            </configuration>
          </plugin>
        </plugins>
      </reporting>
    
    </project>
    
    

    import com.microsoft.playwright.Page;
    
    public class LoginPage {
    
        private Page page;
    
        //Locators
        private final String usernameLocator = "input[name='username']";
        private final String passwordLocator = "input[name='password']";
        private final String submitButton = "button[type='submit']";
        private final String errorMessage = "//p[contains(@class, 'oxd-text oxd-text--p oxd-alert-content-text')]";
    
        //Constructor
        public LoginPage(Page page){
            this.page = page;
        }
    
        public void login(String username, String password) {
            page.fill(usernameLocator,username);
            page.fill(passwordLocator,password);
            page.click(submitButton);
        }
    
        public String getErrorMessage(){
            return page.textContent(errorMessage);
        }
    }
    

    package org.example.pages;
    
    import com.microsoft.playwright.Page;
    
    public class DashboardPage {
    
        private Page page;
    
        //Locators
        private final String dashboardHeading = "//h6[contains(@class, 'oxd-topbar-header-breadcrumb-module')]";
    
        //Constructor
        public DashboardPage(Page page) {
            this.page = page;
        }
    
        // Methods
        public String getHeading() {
            return page.textContent(dashboardHeading);
        }
    }
    

    package org.example.utils;
    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();
        }
    }
    
    Playwright playwright;
    Browser browser = null;
    
    BrowserContext context;
    Page page;
    
      @BeforeAll
        public void launchBrowser() {
            playwright = Playwright.create();
            browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
        }
    

    @BeforeMethod
    void createContextAndPage() {
          context = browser.newContext();
          page = context.newPage();
          page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    }
    
    @AfterAll
     public static void closeBrowser() {
            playwright.close();
     }
    
    @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;
    
    public class LoginTests extends BaseTests {
    
        @Test
        public void unsuccessfulLogin() {
    
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("abc","abc");
            String actualErrorMessage = loginPage.getErrorMessage();
            Assertions.assertEquals("Invalid credentials", actualErrorMessage, "");
    
       }
    
        @Test
        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");
    
        }
    
    }
    

    mvn clean test site
    

    Setup Playwright Java with JUnit5: A Comprehensive Guide

    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_Junit5_Demo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>Playwright_Junit5_Demo</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>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>
        <maven.site.plugin.version>4.0.0-M16</maven.site.plugin.version>
        <maven.surefire.report.plugin.version>3.5.4</maven.surefire.report.plugin.version>
      </properties>
    
      <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>
    
      </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>
            </configuration>
          </plugin>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-site-plugin</artifactId>
            <version>${maven.site.plugin.version}</version>
          </plugin>
        </plugins>
      </build>
    
      <reporting>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-report-plugin</artifactId>
            <version>${maven.surefire.report.plugin.version}</version>
            <configuration>
              <outputName>JUnit5 Report</outputName>
            </configuration>
          </plugin>
        </plugins>
      </reporting>
    
    </project>
    

    <reporting>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-report-plugin</artifactId>
            <version>${maven.surefire.report.plugin.version}</version>
            <configuration>
              <outputName>JUnit5 Report</outputName>
            </configuration>
          </plugin>
        </plugins>
      </reporting>
    
    

    package com.example;
    
    import com.microsoft.playwright.Browser;
    import com.microsoft.playwright.BrowserContext;
    import com.microsoft.playwright.Page;
    import com.microsoft.playwright.Playwright;
    import org.junit.jupiter.api.*;
    
    // Subclasses will inherit PER_CLASS behavior.
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    public class BaseClass {
    
        // Shared between all tests in the class.
        Playwright playwright;
        Browser browser;
    
        @BeforeAll
        void launchBrowser() {
            playwright = Playwright.create();
            browser = playwright.chromium().launch();
    
        }
    
        @AfterAll
        void closeBrowser() {
            playwright.close();
        }
    
        // New instance for each test method.
        BrowserContext context;
        Page page;
    
        @BeforeEach
        void createContextAndPage() {
            context = browser.newContext();
            page = context.newPage();
            page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
        }
    
        @AfterEach
        void closeContext() {
            context.close();
        }
    }
    

    Playwright playwright;
    Browser browser;
    
    BrowserContext context;
    Page page;
    
    @BeforeEach
        void createContextAndPage() {
            context = browser.newContext();
            page = context.newPage();
            page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
        }
    
    @AfterEach
        void closeContext() {
            context.close();
        }
    
    @AfterAll
        void closeBrowser() {
            playwright.close();
        }
    

    package com.example;
    
    import org.junit.jupiter.api.Test;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    public class PlaywrightTests extends BaseClass{
    
        @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");
        }
    }
    
    

    mvn clean test site
    

    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
    

    How to run parameterized Selenium test using JUnit5

    HOME

    The previous tutorial has shown the various parameterized tests in JUnit5. This tutorial shows how to run a Selenium test multiple times with a different set of data. This helps to reduce the duplication of code. This is a very common scenario in any testing. Imagine, we want to test the requirement for a login page that uses a username and password to log in to the application. Username and password must satisfy some conditions like username can be only alphabets and no numeric and special characters. There could be multiple sets of data that can be used to test this requirement.

    Prerequisite:

    1. Selenium – 4.21.0
    2. Maven – 3.9.6
    3. Java 17
    4. JUnit Jupiter Engine – 5.11.0-M2
    5. JUnit Jupiter API – 5.11.0-M2

    JUnit5 provides a lot of ways to parameterize a test – @ValueSource, @EnumSource, @MethodSource, @CsvSource, @CsvFileSource, and @ArgumentsSource.

    Let us see an example where the test is not parameterized. In the below example, we want to verify the different error messages generated by passing incorrect values to username and password.

    This is the base class – Login, which contains the test method that uses a different set of test data.

    package com.example.parameterized;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import org.openqa.selenium.support.PageFactory;
    
    public class LoginPage {
    
        WebDriver driver ;
    
        @FindBy(name="username")
        WebElement username;
    
        @FindBy(name="password")
        WebElement password;
    
        @FindBy(xpath="//*[@class='oxd-form']/div[3]/button")
        WebElement loginButton;
    
        @FindBy(xpath="//*[@class='orangehrm-login-error']/div[1]/div[1]/p")
        WebElement actualErrorMessage;
    
    
        public LoginPage(WebDriver driver) {
    
            this.driver = driver;
    
            // This initElements method will create all WebElements
            PageFactory.initElements(driver, this);
        }
    
        public void setUserName(String strUserName) {
            username.sendKeys(strUserName);
        }
    
        // Set password in password textbox
        public void setPassword(String strPassword) {
            password.sendKeys(strPassword);
        }
    
        // Click on login button
        public void clickLogin() {
            loginButton.click();
        }
    
        // Get the error message
        public String getErrorMessage() {
            return actualErrorMessage.getText();
        }
    
        public void login(String strUserName, String strPasword) {
    
            // Fill user name
            this.setUserName(strUserName);
    
            // Fill password
            this.setPassword(strPasword);
    
            // Click Login button
            this.clickLogin();
        }
    
    }
    

    The example below shows 4 tests using a common test with 4 different sets of data.

    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    import java.time.Duration;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    public class NonParameterizedLoginTest {
    
        WebDriver driver;
        LoginPage login;
    
        @BeforeEach
        void setUp() {
    
            ChromeOptions chromeOptions = new ChromeOptions();
            driver = new ChromeDriver(chromeOptions);
            driver.manage().window().maximize();
            driver.get("https://opensource-demo.orangehrmlive.com/");
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
    
        }
    
        @Test
        void invalidCredentials1() {
    
            login = new LoginPage(driver);
            login.login("Admin","Admin");
            String actualErrorMessage = login.getErrorMessage();
            assertEquals("Invalid credentials", actualErrorMessage);
    
        }
    
        @Test
        void invalidCredentials2() {
    
            login = new LoginPage(driver);
            login.login("admin","Admin");
            String actualErrorMessage = login.getErrorMessage();
            assertEquals("Invalid credentials", actualErrorMessage);
    
        }
    
        @Test
        void invalidCredentials3() {
    
            login = new LoginPage(driver);
            login.login("Admin","123");
            String actualErrorMessage = login.getErrorMessage();
            assertEquals("Invalid credentials", actualErrorMessage);
    
        }
    
        @Test
        void invalidCredentials4() {
    
            login = new LoginPage(driver);
            login.login("admin123","3456admin");
            String actualErrorMessage = login.getErrorMessage();
            assertEquals("Invalid credentials", actualErrorMessage);
    
        }
    
        @AfterEach
        void tearDown() {
            if (driver != null) {
                driver.close();
            }
        }
    
    }
    

    We can see that the same method is called multiple times. This is a duplication of code. The output of the above program is

    Now, we will parameterize the same test. To do so, we need to add a dependency to the POM.xml.

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.example</groupId>
      <artifactId>JUnit5_Examples</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>JUnit5_Examples</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <selenium.version>4.21.0</selenium.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.seleniumhq.selenium</groupId>
          <artifactId>selenium-java</artifactId>
          <version>${selenium.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-params</artifactId>
          <version>${junit.jupiter.params.version}</version>
          <scope>test</scope>
        </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>
    
    

    There are multiple ways to parameterize the test. To start with:

    1. Replace the @Test annotation with the @ParameterizedTest annotation provided by the JUnit5 framework.
    2. Add parameters to the loginTest() method. In this example, we will add a username and a password parameter.
    3. Add the parameters source. In this example, we will use the @CsvFileSource annotation.

    To know all the different types of parameterization methods, please refer to this tutorial. This tutorial will show the 2 most common ways to parameterize tests in JUnit5.

    1.@CsvSource

    @CsvSource allows us to express argument lists as comma-separated values (i.e., CSV String literals). Each string provided via the value attribute in @CsvSource represents a CSV record and results in one invocation of the parameterized test. An empty, quoted value (”) results in an empty String. This can be seen in the example below.

    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.CsvSource;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    import java.time.Duration;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    public class ParameterizedSourceTest {
    
        WebDriver driver;
    
        LoginPage loginPage;
    
        @BeforeEach
        void setUp() {
    
            ChromeOptions chromeOptions = new ChromeOptions();
            driver = new ChromeDriver(chromeOptions);
            driver.manage().window().maximize();
            driver.get("https://opensource-demo.orangehrmlive.com/");
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));
    
        }
    
        @ParameterizedTest
        @CsvSource({
                "admin123,admin123,Invalid credentials",
                "admin,admin12,Invalid credentials",
                "Admin,1234,Invalid credentials",
                "12345,%^$£56,Invalid credentials"
        })
    
        void invalidCredentials1(String username, String password, String errorMessage) {
    
            loginPage = new LoginPage(driver);
            loginPage.login(username,password);
            String actualErrorMessage = loginPage.getErrorMessage();
            assertEquals(errorMessage, actualErrorMessage);
    
        }
    
        @AfterEach
        void tearDown() {
            driver.close();
        }
    }
    

    The output of the above program is

    2. @CsvFileSource

    @CsvFileSource lets us use comma-separated value (CSV) files from the classpath or the local file system.

    We can see in the example below that we have skipped the first line from the credentials.csv file as it is the heading of the file. invalidCredentials() method got 4 different set of the test data from CSV file using parameterization. JUnit5 ignores the headers via the numLinesToSkip attribute.

    In @CsvFileSource, an empty, quoted value (“”) results in an empty String in JUnit5.

    package com.example.parameterized;
    
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.CsvFileSource;
    import org.junit.jupiter.params.provider.CsvSource;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    import java.time.Duration;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    public class ParameterizedFileTest {
    
        WebDriver driver;
    
        LoginPage loginPage;
    
        @BeforeEach
        void setUp() {
    
            ChromeOptions chromeOptions = new ChromeOptions();
            driver = new ChromeDriver(chromeOptions);
            driver.manage().window().maximize();
            driver.get("https://opensource-demo.orangehrmlive.com/");
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(6));
    
        }
    
        @ParameterizedTest
        @CsvFileSource(files = "src/test/resources/credentials.csv", numLinesToSkip = 1)
        void invalidCredentials1(String username, String password, String errorMessage) {
    
            loginPage = new LoginPage(driver);
            loginPage.login(username,password);
            String actualErrorMessage = loginPage.getErrorMessage();
            assertEquals(errorMessage, actualErrorMessage);
    
        }
    
        @AfterEach
        void tearDown() {
            driver.close();
        }
    }
    

    The result of the above program is

    Congratulations!! We have seen how Selenium tests are parameterized in JUnit5. Happy Learning.

    How to Retry Test in JUnit5 – @RepeatedTest

    HOME

    In JUnit5, JUnit Jupiter provides the ability to repeat a test a specified number of times by annotating a method with @RepeatedTest. We can specify the repetition frequency as a parameter to the @RepeatedTest annotation.

    When do we use the Repeated Test?

    Imagine, we are testing an online shopping website. In the process of placing an order, we need to pay for the product. But the payment gateway is a third-party service, and we cannot control the connectivity between our website and the payment gateway. We know that clicking on the ‘Payment’ link sometime shows “Exception: Page cannot be displayed”. This is an intermittent issue. So, we don’t want to fail the test if this payment link does not work. We can configure it to click this payment link multiple times, before marking the test case failed. Here comes the Repeated Test in the picture.

    A few points to keep in mind for @RepeatedTest are as follows:

    1. The methods annotated with @RepeatedTest cannot be static, otherwise, the test cannot be found.
    2. The methods annotated with @RepeatedTest cannot be private, otherwise, the test cannot be found.
    3. The return type of the method annotated with @RepeatedTest must be void only, otherwise, the test cannot be found.

    The below example will run the test 5 times.

     @DisplayName("Addition")
     @RepeatedTest(3)
     void repeatTest(){
        int a = 4;
        int b = 6;
        assertEquals(10, a+b,"Incorrect sum of numbers");
     }
    

    The output of the above test:

    Each invocation of a repeated test behaves like the execution of a regular @Test method, with full support for the same lifecycle callbacks and extensions.

    It means that @BeforeEach and @AfterEach annotated lifecycle methods will be invoked for each invocation of the test.

    @BeforeEach annotation is used to signal that the annotated method should be executed before each invocation of the @Test@RepeatedTest@ParameterizedTest, or @TestFactory method in the current class. This is the replacement of the @Before Method in JUnit4.

    TestInfo is used to inject information about the current test or container into @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll methods.
    If a method parameter is of type TestInfo, JUnit will supply an instance of TestInfo corresponding to the current test or container as the value for the parameter.

    RepetitionInfo is used to inject information about the current repetition of a repeated test into the @RepeatedTest, @BeforeEach, and @AfterEach methods.
    If a method parameter is of type RepetitionInfo, JUnit will supply an instance of RepetitionInfo corresponding to the current repeated test as the value for the parameter.

    In the below example, @BeforeEach will get executed before each repetition of each repeated test. By having the TestInfo and RepetitionInfo injected into the method, we see that it’s possible to obtain information about the currently executing repeated test.

    import org.junit.jupiter.api.*;
    import static org.junit.jupiter.api.Assertions.*;
    
    public class RepeatCycleDemo {
    
        @BeforeEach
        void init(TestInfo testInfo, RepetitionInfo repetitionInfo) {
          System.out.println("Before Each init() method called");
          int currentRepetition = repetitionInfo.getCurrentRepetition();
          int totalRepetitions = repetitionInfo.getTotalRepetitions();
          String methodName = testInfo.getTestMethod().get().getName();
          System.out.println(String.format("About to execute repetition %d of %d for %s", currentRepetition, totalRepetitions, methodName));
         }
    
        @RepeatedTest(3)
        void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
          int a = 4;
          int b = 6;
          assertEquals(10, a+b, repetitionInfo.getTotalRepetitions());
        }
    
        @AfterEach
        public void cleanUpEach(){
          System.out.println("=================After Each cleanUpEach() method called =================");
        }
    }
    

    The output of the above test:

    Custom Display Name

    In addition to specifying the number of repetitions, a custom display name can be configured for each repetition via the name attribute of the @RepeatedTest annotation.

    The display name can be a pattern composed of a combination of static text and dynamic placeholders. The following placeholders are currently supported.

    1. {displayName}: display name of the @RepeatedTest method
    2. {currentRepetition}: the current repetition count
    3. {totalRepetitions}: the total number of repetitions

        @BeforeEach
        void init(TestInfo testInfo, RepetitionInfo repetitionInfo) {
            System.out.println("Before Each init() method called");
            int currentRepetition = repetitionInfo.getCurrentRepetition();
            int totalRepetitions = repetitionInfo.getTotalRepetitions();
            String methodName = testInfo.getTestMethod().get().getName();
            System.out.println(String.format("About to execute repetition %d of %d for %s", //
                    currentRepetition, totalRepetitions, methodName));
        }
    
       //Custom Display  
        @RepeatedTest(value = 2, name = "{displayName} {currentRepetition}/{totalRepetitions}")
        @DisplayName("Repeat JUnit5 Test")
        void customDisplayName(TestInfo testInfo) {
            assertEquals("Repeat JUnit5 Test 1/2", testInfo.getDisplayName());
        }
    

    The output of the above test:

    The default display name for a given repetition is generated based on the following pattern: “repetition {currentRepetition} of {totalRepetitions}”. Thus, the display names for individual repetitions of the previous repeatedTest() example would be repetition 1 of 10, and repetition 2 of 10.

    We can use one of two predefined formats for displaying the name – LONG_DISPLAY_NAME and SHORT_DISPLAY_NAME. The latter is the default format if none is specified.

    1. RepeatedTest.LONG_DISPLAY_NAME – {displayName} :: repetition {currentRepetition} of {totalRepetitions}
    2. RepeatedTest.SHORT_DISPLAY_NAME – repetition {currentRepetition} of {totalRepetitions}

    Below is an example of SHORT_DISPLAY_NAME

        @RepeatedTest(value = 3, name = RepeatedTest.SHORT_DISPLAY_NAME)
        @DisplayName("Multiplication")
        void customDisplayNameWithShortPattern() {
            assertEquals(8, 6*5);
     }
    

    In this case, the name is displayed as Multiplication repetition 1 of 3, repetition 2 of 3, and soon.

    The output of the above test:

    Below is an example of LONG_DISPLAY_NAME

      @RepeatedTest(value = 3, name = RepeatedTest.LONG_DISPLAY_NAME)
        @DisplayName("Addition")
        void customDisplayNameWithLongPattern(TestInfo testInfo) {
            System.out.println("Display Name :"+ testInfo.getDisplayName());
            System.out.println("Test Class Name :"+ testInfo.getTestClass());
            System.out.println("Test Method :"+ testInfo.getTestMethod());
            assertEquals(8, 3+7);
        }
    
    

    The output of the above test:

    As we can see in the example, we have used @DisplayName(“Addition”), but as it is name = RepeatedTest.LONG_DISPLAY_NAME, so the name of the tests are now Addition :: repetition 1 of 3, Addition :: repetition 2 of 3 and soon.

    Congratulations. We are able to execute the tests multiple times by using the @RepeatedTest annotation. Happy Learning!!

    How to disable tests in JUnit5 – @Disabled

    HOME

    JUnit5 also provides the support to exclude/disable the tests. The @Disabled annotation in JUnit5 is used to exclude the test methods from the test suite. This annotation can be applied over a test class as well as over individual test methods. This annotation accepts only one optional parameter where we can mention the reason to skip the tests. @Disabled annotation can be used without providing any reason but its always good to provide a reason why this particular test case has been disabled, or issue tracker id for better understanding.

    1.Disable Test Methods

    In the below example, I have annotated 2 test methods out of 5 test methods as @Disabled with a parameter which specify the reason for disabling the test that means these 2 test methods should not be executed.

    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Disabled;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    public class DisabledTestsDemo {
    
        WebDriver driver;
    
        @BeforeEach
        public void setUp() {
    
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.addArguments("--start-maximized");
            driver = new ChromeDriver(chromeOptions);
            driver.get("https://duckduckgo.com/");
    
        }
    
        @Disabled("This test is blocked till bug 1290 is fixed")
        @Test
        void verifyBrowserText() {
            boolean displayed = driver.findElement(By.xpath("//section[@class='homepage-cta-section_ctaSection__o_ioD']/h2")).isDisplayed();
            assertTrue(displayed);
    
        }
    
        @Test
        void verifyPageTitle() {
    
            String pageTitle = driver.getTitle();
            assertEquals("DuckDuckGo — Privacy, simplified.", pageTitle);
    
        }
    
        @Test
        void verifyDownloadBrowserButton() {
    
            boolean downloadBrowserBtn = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/a/span")).isDisplayed();
            assertTrue(downloadBrowserBtn);
        }
    
        @Test
        void displaySearchBox() {
    
            boolean searchBoxDisplayed = driver.findElement(By.xpath("//*[@id=\"searchbox_input\"]")).isEnabled();
            assertTrue(searchBoxDisplayed);
        }
    
        @Disabled("This test is not applicable for Sprint 14")
        @Test
        void verifyDefaultSearchButtonText() {
    
            String defaultSearchBtnText = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/h2")).getText();
            assertEquals("Free. Fast. Private. Get our browser on all your devices.",(defaultSearchBtnText));
        }
    
        @AfterEach
        public void tearDown() {
            driver.close();
        }
    }
    

    The output of the above test shows, the 2 tests that are annotated with @Disabled are not executed.

    2. Disable Test Class

    When we annotate a class as @Disabled, then all the test methods present within that test class will not be executed.

    In the below example, there are 2 test classes – Demo and DisabledTestsDemo. Demo class contains 1 test method whereas DisabledTestsDemo contains 5 test methods. I have annotated DisabledTestsDemo class as @Disabled which means all 5 tests present within it will not be executed.

    In the below example, there is a base class that contains the initialization of webDriver as well as closing of the same.

    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    public class Base {
    
        static WebDriver driver=null;
    
        @BeforeEach
        public void setUp() {
    
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.addArguments("--start-maximized");
            driver = new ChromeDriver(chromeOptions);
            driver.get("https://duckduckgo.com/");
    
        }
    
        @AfterEach
        public void tearDown() {
            driver.close();
        }
    }
    

    Class 1 – Demo

    import org.junit.jupiter.api.Test;
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    public class NonDisabledClass extends Base {
    
        @Test
        void verifyPageTitle() {
    
            String pageTitle = driver.getTitle();
            assertEquals("DuckDuckGo — Privacy, simplified.", pageTitle);
    
        }
    }
    
    

    Class 2 – DisabledTestsDemo

    import org.junit.jupiter.api.Disabled;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.By;
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    @Disabled
    public class DisabledClassDemo extends Base {
    
        @Test
        void verifyBrowserText() {
            boolean displayed = driver.findElement(By.xpath("//section[@class='homepage-cta-section_ctaSection__o_ioD']/h2")).isDisplayed();
            assertTrue(displayed);
    
        }
    
        @Test
        void verifyDownloadBrowserButton() {
    
            boolean downloadBrowserBtn = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/a/span")).isDisplayed();
            assertTrue(downloadBrowserBtn);
        }
    
        @Test
        void displaySearchBox() {
    
            boolean searchBoxDisplayed = driver.findElement(By.xpath("//*[@id=\"searchbox_input\"]")).isEnabled();
            assertTrue(searchBoxDisplayed);
        }
    
        @Test
        void verifyDefaultSearchButtonText() {
    
            String defaultSearchBtnText = driver.findElement(By.xpath("//*[@id=\"features\"]/div[1]/section[1]/div/div[1]/div[1]/div[2]/div[1]/h2")).getText();
            assertEquals("Free. Fast. Private. Get our browser on all your devices.",(defaultSearchBtnText));
        }
    }
    
    

    The output of the above test shows, all the test methods present in the class that is annotated with @Disabled are not executed.

    Congratulations. We are able to understand the usage of @Disabled annotation in JUnit5. Happy Learning!!