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

    Playwright Tutorials – TypeScript

    HOME

    Integrate Allure Report with Playwright with Java and JUnit5

    Last Updated On

    HOME

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

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

    Table of Contents

    System requirements

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

    Dependency List

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

    Implementation Steps

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

    Step 2 – Add dependencies to pom.xml

    Add Playwright, JUnit Jupiter Engine, JUnit Jupiter API, JUnit Param, JUnit Platform and Allure-JUnit5 dependencies to pom.xml (Maven Project).

     <dependencyManagement>
          <dependencies>
            <dependency>
              <groupId>io.qameta.allure</groupId>
              <artifactId>allure-bom</artifactId>
              <version>${allure.version}</version>
              <type>pom</type>
              <scope>import</scope>
            </dependency>
          </dependencies>
        </dependencyManagement>
    
      <dependencies>
    
        <dependency>
          <groupId>com.microsoft.playwright</groupId>
          <artifactId>playwright</artifactId>
          <version>${playwright.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-engine</artifactId>
          <version>${junit.jupiter.engine.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-api</artifactId>
          <version>${junit.jupiter.api.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-params</artifactId>
          <version>${junit.jupiter.params.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.junit.platform</groupId>
          <artifactId>junit-platform-launcher</artifactId>
          <version>${junit.platform.launcher.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>io.qameta.allure</groupId>
          <artifactId>allure-junit5</artifactId>
          <scope>test</scope>
        </dependency>
    
      </dependencies>
    
    

    Step 3 – Update the Build Section of pom.xml in the Allure Report Project
     <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.plugin.version}</version>
            <configuration>
              <source>${maven.compiler.source.version}</source>
              <target>${maven.compiler.target.version}</target>
            </configuration>
          </plugin>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven.surefire.plugin.version}</version>
            <configuration>
              <argLine>
                -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
              </argLine>
            </configuration>
            <dependencies>
              <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>${aspectj.version}</version>
              </dependency>
            </dependencies>
          </plugin>
    
        </plugins>
      </build>
    

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.example</groupId>
      <artifactId>PageObjectModel_Playwright_JUnit5</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>PageObjectModel_Playwright_JUnit5</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <junit.jupiter.engine.version>6.1.0-M1</junit.jupiter.engine.version>
        <junit.jupiter.api.version>6.1.0-M1</junit.jupiter.api.version>
        <junit.jupiter.params.version>6.1.0-M1</junit.jupiter.params.version>
        <junit.platform.launcher.version>6.1.0-M1</junit.platform.launcher.version>
        <maven.compiler.plugin.version>3.14.1</maven.compiler.plugin.version>
        <maven.compiler.source.version>17</maven.compiler.source.version>
        <maven.compiler.target.version>17</maven.compiler.target.version>
        <maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <maven.site.plugin.version>4.0.0-M16</maven.site.plugin.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25.1</aspectj.version>
      </properties>
    
    
        <!-- Add allure-bom to dependency management to ensure correct versions of all the dependencies are used -->
        <dependencyManagement>
          <dependencies>
            <dependency>
              <groupId>io.qameta.allure</groupId>
              <artifactId>allure-bom</artifactId>
              <version>${allure.version}</version>
              <type>pom</type>
              <scope>import</scope>
            </dependency>
          </dependencies>
        </dependencyManagement>
    
      <dependencies>
    
        <dependency>
          <groupId>com.microsoft.playwright</groupId>
          <artifactId>playwright</artifactId>
          <version>${playwright.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-engine</artifactId>
          <version>${junit.jupiter.engine.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-api</artifactId>
          <version>${junit.jupiter.api.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter-params</artifactId>
          <version>${junit.jupiter.params.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.junit.platform</groupId>
          <artifactId>junit-platform-launcher</artifactId>
          <version>${junit.platform.launcher.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>io.qameta.allure</groupId>
          <artifactId>allure-junit5</artifactId>
          <scope>test</scope>
        </dependency>
    
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.plugin.version}</version>
            <configuration>
              <source>${maven.compiler.source.version}</source>
              <target>${maven.compiler.target.version}</target>
            </configuration>
          </plugin>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven.surefire.plugin.version}</version>
            <configuration>
              <argLine>
                -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
              </argLine>
            </configuration>
            <dependencies>
              <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>${aspectj.version}</version>
              </dependency>
            </dependencies>
          </plugin>
        </plugins>
      </build>
    
    </project>
    
    
    

    2. Project Structure for Maintainability

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

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

    package com.example.pages;
    
    import com.microsoft.playwright.Locator;
    import com.microsoft.playwright.Page;
    import io.qameta.allure.Step;
    
    public class LoginPage {
    
        private final Page page;
    
        // Locators
        private final Locator usernameLocator;
        private final Locator passwordLocator;
        private final Locator submitLocator;
        private final Locator invalidCredentialsLocator;
        private final Locator missingUsernameErrorMessageLocator;
    
        public LoginPage(Page page) {
            this.page = page;
            this.usernameLocator = page.locator("input[name='username']");
            this.passwordLocator = page.locator("input[name='password']");
            this.submitLocator = page.locator("button[type='submit']");
            this.invalidCredentialsLocator = page.locator("//p[contains(@class, \"oxd-text oxd-text--p oxd-alert-content-text\")]");
            this.missingUsernameErrorMessageLocator = page.locator("//span[contains(@class, 'oxd-text oxd-text--span oxd-input-field-error-message oxd-input-group__message')]");
        }
    
        @Step("Enter credentials")
        public void login(String user, String pass){
            usernameLocator.fill(user);
            passwordLocator.fill(pass);
            submitLocator.click();
        }
    
        @Step("Get Error Message for invalid credentials")
        public String getErrorMessage () {
            return invalidCredentialsLocator.textContent();
        }
    
        @Step("Get Error Message for missing username")
        public String getMissingUsernameErrorMessage () {
            return missingUsernameErrorMessageLocator.textContent();
        }
    }
    
    
    package com.example.pages;
    
    import com.microsoft.playwright.Locator;
    import com.microsoft.playwright.Page;
    import io.qameta.allure.Step;
    
    public class DashboardPage {
    
        private Page page;
    
        private final Locator headingLocator;
    
        public DashboardPage(Page page){
            this.page = page;
            this.headingLocator = page.locator("//h6[contains(@class, \"oxd-topbar-header-breadcrumb-module\")]");
            this.assignLeaveLocator = page.locator("//[contains(@text, \"Assign Leave\")]");
            this.leaveListLocator = page.getByTitle("Leave List");
    
        }
    
        @Step("Get Heading of Dashboard page")
        public String getDashboardPageHeading() {
            return headingLocator.textContent();
        }
    
    }
    
    

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

    package com.example.tests;
    
    import com.example.pages.DashboardPage;
    import com.example.pages.LoginPage;
    import com.example.utils.BaseTests;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.CsvFileSource;
    import io.qameta.allure.Description;
    import io.qameta.allure.Issue;
    import io.qameta.allure.Link;
    import io.qameta.allure.Owner;
    import io.qameta.allure.Severity;
    import io.qameta.allure.TmsLink;
    import org.junit.jupiter.api.DisplayName;
    
    import static io.qameta.allure.SeverityLevel.CRITICAL;
    
    public class LoginTests extends BaseTests {
    
        @ParameterizedTest
        @CsvFileSource(files = "src/test/resources/testData/credentials.csv", numLinesToSkip = 1)
        @DisplayName("Login Authentication")
        @Description("This test attempts to log into the website using a incorrect username and a password. Fails if any error happens.")
        @Severity(CRITICAL)
        @Owner("Vibha Singh")
        @Link(name = "Website", url = "https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
        @Issue("AUTH-123")
        @TmsLink("TMS-456")
        public void unsuccessfulLogin(String username, String password, String expectedErrorMessage) {
    
            LoginPage loginPage = new LoginPage(page);
            loginPage.login(username,password);
            String actualErrorMessage = loginPage.getErrorMessage();
            Assertions.assertEquals(expectedErrorMessage, actualErrorMessage, "Incorrect error message is displayed");
    
       }
    
        @Test
        @DisplayName("Successful Login Authentication")
        @Description("This test attempts to log into the website using a correct username and a password. Fails if any error happens.")
        @Severity(CRITICAL)
        @Owner("Vibha Singh")
        @Link(name = "Website", url = "https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
        @Issue("AUTH-124")
        @TmsLink("TMS-460")
        public void successfulLogin() {
    
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("Admin","admin123");
            DashboardPage dashboardPage = new DashboardPage(page);
            String actualHeading = dashboardPage.getDashboardPageHeading();
            Assertions.assertEquals("Dashboard",actualHeading, "Unable to login to the application");
    
        }
    
    }
    
    @Description("This test attempts to log into the website using a invalid login and a password that result in error")
    

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

    7. Run the Tests and Generate Allure Report

    To run the tests, use the below command

    mvn clean test
    

    The output of the above program is

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

    8. How to Generate an Allure Report

    Use the command below to generate the Allure Report

     allure serve build/allure-results
    

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

    Graphs in Allure Report

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

    Timeline in Allure Report

    The timeline tab visualizes retrospective test execution. Allure adaptors collect precise timings of tests. Here on this tab, they are arranged according to their sequential or parallel timing structure.

     allure awesome build/allure-results
    

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

    Congratulations!! We have integrated an allure report with Playwright, Java, and JUnit5. I hope this tutorial is useful to you.

    Additional Tutorials on Allure Reports

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

    Integrate Allure Report with Playwright with Java and TestNG

    Last Updated On

    HOME

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

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

    Table of Contents

    System requirements

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

    Dependency List

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

    High-Level Execution Flow

    Implementation Steps

    Step 1 – Update the Properties section in Maven pom.xml
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <testng.version>7.11.0</testng.version>
        <allure.version>2.32.0</allure.version>
        <aspectj.version>1.9.25</aspectj.version>
        <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
        <maven.compiler.source.version>17</maven.compiler.source.version>
        <maven.compiler.target.version>17</maven.compiler.target.version>
        <maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
      </properties>
    

    Step 2 – Add dependencies to pom.xml

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

     <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>io.qameta.allure</groupId>
                    <artifactId>allure-bom</artifactId>
                    <version>${allure.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
    
            <!-- Playwright -->
            <dependency>
                <groupId>com.microsoft.playwright</groupId>
                <artifactId>playwright</artifactId>
                <version>${playwright.version}</version>
            </dependency>
    
            <!-- TestNG -->
            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>${testng.version}</version>
                <scope>test</scope>
            </dependency>
    
            <!-- Allure-TestNG -->
            <dependency>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-testng</artifactId>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    
    

    Step 3 – Update the Build Section of pom.xml in the Allure Report Project
     <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven.compiler.plugin.version}</version>
                    <configuration>
                        <source>${maven.compiler.source.version}</source>
                        <target>${maven.compiler.target.version}</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>${maven.surefire.plugin.version}</version>
                    <configuration>
                        <suiteXmlFiles>
                            <suiteXmlFile>testng.xml</suiteXmlFile>
                        </suiteXmlFiles>
                        <argLine>
                            -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                        </argLine>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjweaver</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </build>
    

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example</groupId>
        <artifactId>Playwright_PageObjectModel</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>Playwright_PageObjectModel</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <playwright.version>1.57.0</playwright.version>
            <testng.version>7.11.0</testng.version>
            <allure.version>2.32.0</allure.version>
            <aspectj.version>1.9.25</aspectj.version>
            <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
            <maven.compiler.source.version>17</maven.compiler.source.version>
            <maven.compiler.target.version>17</maven.compiler.target.version>
            <maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
        </properties>
    
        <!-- Add allure-bom to dependency management to ensure correct versions of all the dependencies are used -->
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>io.qameta.allure</groupId>
                    <artifactId>allure-bom</artifactId>
                    <version>${allure.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <dependencies>
    
            <!-- Playwright -->
            <dependency>
                <groupId>com.microsoft.playwright</groupId>
                <artifactId>playwright</artifactId>
                <version>${playwright.version}</version>
            </dependency>
    
            <!-- TestNG -->
            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>${testng.version}</version>
                <scope>test</scope>
            </dependency>
    
            <!-- Allure-TestNG -->
            <dependency>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-testng</artifactId>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>${maven.compiler.plugin.version}</version>
                    <configuration>
                        <source>${maven.compiler.source.version}</source>
                        <target>${maven.compiler.target.version}</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>${maven.surefire.plugin.version}</version>
                    <configuration>
                        <suiteXmlFiles>
                            <suiteXmlFile>testng.xml</suiteXmlFile>
                        </suiteXmlFiles>
                        <argLine>
                            -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                        </argLine>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjweaver</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </build>
    </project>
    
    
    

    2. Project Structure for Maintainability

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

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

    package com.example.utils;
    
    import io.qameta.allure.Attachment;
    
    public abstract class AllureAttachments {
    
        @Attachment(value = "Failure Screenshot", type = "image/png")
        public static byte[] attachScreenshot(byte[] screenshot) {
            return screenshot;
        }
    }
    
    
    package com.example.utils;
    
    import com.microsoft.playwright.*;
    import org.testng.annotations.*;
    
    public class BaseClass {
    
        // Shared between all tests in this class.
        Playwright playwright;
        Browser browser = null;
    
        // New instance for each test method.
        BrowserContext context;
        public Page page;
    
        public Page getPage() {
            return page;
        }
    
        @BeforeClass
        public void launchBrowser() {
            playwright = Playwright.create();
            browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
        }
    
        @BeforeMethod
        public void createContextAndPage() {
            context = browser.newContext();
            page = context.newPage();
            page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
        }
    
        @AfterMethod
        public void closeContext() {
            context.close();
        }
    
        @AfterClass
        public void closeBrowser() {
            playwright.close();
        }
    }
    

    package com.example.utils;
    
    import com.microsoft.playwright.Page;
    import org.testng.ITestListener;
    import org.testng.ITestResult;
    
    public class TestListener implements ITestListener {
    
         @Override
        public void onTestFailure(ITestResult result) {
            System.out.println("❌ onTestFailure triggered");
            Page page = BaseClass.getPage();
            if (page != null) {
                byte[] screenshot = page.screenshot();
                AllureAttachments.attachScreenshot(screenshot);
            }
        }
    }
    
    

    package com.example.tests;
    
    import com.example.pages.DashboardPage;
    import com.example.pages.LoginPage;
    import com.example.utils.BaseClass;
    import com.example.utils.TestListener;
    import io.qameta.allure.Description;
    import io.qameta.allure.Owner;
    import io.qameta.allure.Severity;
    import org.testng.Assert;
    import org.testng.annotations.Listeners;
    import org.testng.annotations.Test;
    import static io.qameta.allure.SeverityLevel.*;
    
    public class LoginTests extends BaseClass {
    
        @Test
        @Description("This test attempts to log into the website using a invalid login and a password that result in error")
        @Severity(NORMAL)
        @Owner("Vibha Singh")
        public void unsuccessfulLogin() {
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("abc","abc");
            String actualErrorMessage = loginPage.getErrorMessage();
            Assert.assertEquals(actualErrorMessage, "Invalid credentials");
       }
    
        @Test
        @Description("This test attempts to log into the website using a valid login and a password")
        @Severity(CRITICAL)
        @Owner("Vibha Singh")
        public void successfulLogin() {
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("Admin","admin123");
            DashboardPage dashboardPage = new DashboardPage(page);
            String actualHeading = dashboardPage.getDashboardPageHeading();
            Assert.assertEquals(actualHeading, "Dashboard");
        }
    
        @Test
        @Description("This test attempts to log into the website using a blank login and a password that result in error")
        @Severity(MINOR)
        @Owner("Vibha Singh")
        public void missingUsername() {
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("","admin123");
            String actualErrorMessage = loginPage.getMissingUsernameErrorMessage();
            Assert.assertEquals(actualErrorMessage, "Required1");
        }
    
    }
    
    
    @Description("This test attempts to log into the website using a invalid login and a password that result in error")
    

    6. Create testng.xml for the project

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

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

    8. Run the Tests and Generate Allure Report

    To run the tests, use the below command

    mvn clean test
    

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

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

    9. How to Generate an Allure Report

    Use the command below to generate the Allure Report

     allure serve build/allure-results
    

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

    Graphs in Allure Report

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

    Timeline in Allure Report

    The timeline tab visualizes retrospective test execution. Allure adaptors collect precise timings of tests. Here on this tab, they are arranged according to their sequential or parallel timing structure.

     allure awesome build/allure-results
    

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

    Additional Tutorials on Allure Reports

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

    Integration of Playwright 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

    Integration of Playwright with Java, Cucumber and TestNG

    HOME

    Benefits of Using Cucumber with Playwright

    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cucumber.version>7.33.0</cucumber.version>
        <testng.version>7.12.0</testng.version>
        <playwright.version>1.57.0</playwright.version>
        <maven.compiler.version>3.14.1</maven.compiler.version>
        <maven.surefire.version>3.5.4</maven.surefire.version>
        <maven.failsafe.version>3.5.4</maven.failsafe.version>
        <lombok.version>1.18.30</lombok.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    
    <dependencies>
    
        <!-- Cucumber with Java -->
        <dependency>
          <groupId>io.cucumber</groupId>
          <artifactId>cucumber-java</artifactId>
          <version>${cucumber.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- Cucumber with TestNG -->
        <dependency>
          <groupId>io.cucumber</groupId>
          <artifactId>cucumber-testng</artifactId>
          <version>${cucumber.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- TestNG -->
        <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>${testng.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- Playwright -->
        <dependency>
          <groupId>com.microsoft.playwright</groupId>
          <artifactId>playwright</artifactId>
          <version>${playwright.version}</version>
        </dependency>
    
    </dependencies>
    
    

     <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.version}</version>
            <configuration>
              <source>${maven.compiler.source}</source>
              <target>${maven.compiler.target}</target>
            </configuration>
          </plugin>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven.surefire.version}</version>
            <configuration>
              <testFailureIgnore>true</testFailureIgnore>
              <includes>
                <include>**/*RunnerTests.java</include>
              </includes>
            </configuration>
          </plugin>
          
        </plugins>
      </build>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.example</groupId>
      <artifactId>Cucumber_Playwright_TestNG</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>Cucumber_Playwright_TestNG</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cucumber.version>7.33.0</cucumber.version>
        <testng.version>7.12.0</testng.version>
        <playwright.version>1.57.0</playwright.version>
        <maven.compiler.version>3.14.1</maven.compiler.version>
        <maven.surefire.version>3.5.4</maven.surefire.version>
        <maven.failsafe.version>3.5.4</maven.failsafe.version>
        <lombok.version>1.18.30</lombok.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
      </properties>
    
      <dependencies>
    
        <!-- Cucumber with Java -->
        <dependency>
          <groupId>io.cucumber</groupId>
          <artifactId>cucumber-java</artifactId>
          <version>${cucumber.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- Cucumber with TestNG -->
        <dependency>
          <groupId>io.cucumber</groupId>
          <artifactId>cucumber-testng</artifactId>
          <version>${cucumber.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- TestNG -->
        <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>${testng.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!-- Playwright -->
        <dependency>
          <groupId>com.microsoft.playwright</groupId>
          <artifactId>playwright</artifactId>
          <version>${playwright.version}</version>
        </dependency>
    
      </dependencies>
     
     <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.version}</version>
            <configuration>
              <source>${maven.compiler.source}</source>
              <target>${maven.compiler.target}</target>
            </configuration>
          </plugin>
    
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven.surefire.version}</version>
            <configuration>
              <testFailureIgnore>true</testFailureIgnore>
              <includes>
                <include>**/*RunnerTests.java</include>
              </includes>
            </configuration>
          </plugin>
          
        </plugins>
      </build>
    </project>
    

    Feature: Login to HRM Application
    
      Background:
        Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
    
      @ValidCredentials
      Scenario: Login with valid credentials
    
        When User enters username as "Admin" and password as "admin123"
        Then User should be able to login successfully and new page 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 "Required1" 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.steps.BaseStep;
    import com.example.pages.DashboardPage;
    import com.example.pages.LoginPage;
    import io.cucumber.java.en.Given;
    import io.cucumber.java.en.Then;
    import io.cucumber.java.en.When;
    import org.testng.Assert;
    
    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) {
            Assert.assertEquals(loginPage.getErrorMessage(), expectedErrorMessage);
        }
    
        @Then("User should be able to see a message {string} below Username")
        public void userShouldBeAbleToSeeAMessageBelowUsername(String expectedErrorMessage) {
            Assert.assertEquals(loginPage.getMissingUsernameErrorMessage(), expectedErrorMessage);
        }
    
        @Then("User should be able to login successfully and new page opens with heading {string}")
        public void userShouldBeAbleToLoginSuccessfullyAndNewPageOpen(String expectedHeading) {
            dashboardPage = new DashboardPage(getPage());
            Assert.assertEquals(dashboardPage.getDashboardPageHeading(), expectedHeading);
    
        }
    
    }
    

    package com.example.runner;
    
    import io.cucumber.testng.AbstractTestNGCucumberTests;
    import io.cucumber.testng.CucumberOptions;
    
    @CucumberOptions(features = "src/test/resources/features/LoginPage.feature",
            glue = {"com.example.hooks","com.example.definitions"},
            plugin = {
                    "pretty",
            }
    )
    
    public class RunnerTests extends AbstractTestNGCucumberTests {
    
    }
    

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="Playwright test suite" thread-count="3">
        <test name="Chromium Tests">
            <classes>
                <class name="com.example.runner.RunnerTests"/>
            </classes>
        </test>
    </suite>
    

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

    Mastering Page Object Model for Playwright with Java and TestNG

    HOME

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.example</groupId>
      <artifactId>Playwright_TestNG_Demo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>Playwright_TestNG_Demo</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <testng.version>7.11.0</testng.version>
        <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
        <maven.compiler.source.version>17</maven.compiler.source.version>
        <maven.compiler.target.version>17</maven.compiler.target.version>
        <maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
      </properties>
    
      <dependencies>
    
        <dependency>
          <groupId>com.microsoft.playwright</groupId>
          <artifactId>playwright</artifactId>
          <version>${playwright.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>${testng.version}</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.plugin.version}</version>
            <configuration>
              <source>${maven.compiler.source.version}</source>
              <target>${maven.compiler.target.version}</target>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven.surefire.plugin.version}</version>
            <configuration>
              <suiteXmlFiles>
                <suiteXmlFile>testng.xml</suiteXmlFile>
              </suiteXmlFiles>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    

    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;
    
    import com.microsoft.playwright.*;
    import org.testng.annotations.AfterClass;
    import org.testng.annotations.AfterMethod;
    import org.testng.annotations.BeforeClass;
    import org.testng.annotations.BeforeMethod;
    
    public class BaseTests {
    
        // Shared between all tests in this class.
        protected Playwright playwright;
        protected Browser browser;
    
        // New instance for each test method.
        protected BrowserContext context;
        protected Page page;
    
        @BeforeClass
        public void launchBrowser() {
            playwright = Playwright.create();
            browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
        }
    
        @BeforeMethod
        public void createContextAndPage() {
            context = browser.newContext();
            page = context.newPage();
            page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
        }
    
        @AfterMethod
        public void closeContext() {
            context.close();
        }
    
        @AfterClass
        public void closeBrowser() {
            playwright.close();
        }
    }
    
    Playwright playwright;
    Browser browser = null;
    
    BrowserContext context;
    Page page;
    
    @BeforeClass
    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");
    }
    
    @AfterMethod
    void closeContext() {
           context.close();
    }
    
    @AfterClass
    void closeBrowser() {
          playwright.close();
    }
    

    package org.example.tests;
    
    import org.example.pages.DashboardPage;
    import org.example.pages.LoginPage;
    import org.example.utils.BaseTests;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    public class LoginTests extends BaseTests {
    
        @Test
        public void loginToApplication(){
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("Admin","admin123");
            DashboardPage dashboardPage = new DashboardPage(page);
            String actualHeading = dashboardPage.getHeading();
            Assert.assertEquals(actualHeading,"Dashboard", "Unable to login to the application");
        }
    
        @Test
        public void invalidCredentials() {
            LoginPage loginPage = new LoginPage(page);
            loginPage.login("Playwright","test");
            Assert.assertEquals(loginPage.getErrorMessage(), "Invalid credentials" ,"Incorrect Error Message is displayed");
    
        }
    }
    

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="Page Object Model Playwright test suite">
        <test name="Chrome Test">
            <parameter name="browser" value="chromium" />
            <classes>
                <class name="org.example.tests.LoginTests"/>
            </classes>
        </test>
    </suite>    
    

    Cross Browser Testing with Playwright and Java

    HOME

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.example</groupId>
      <artifactId>Playwright_TestNG_Demo</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>Playwright_TestNG_Demo</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <playwright.version>1.57.0</playwright.version>
        <testng.version>7.11.0</testng.version>
        <maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
        <maven.compiler.source.version>17</maven.compiler.source.version>
        <maven.compiler.target.version>17</maven.compiler.target.version>
        <maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
      </properties>
    
      <dependencies>
    
        <dependency>
          <groupId>com.microsoft.playwright</groupId>
          <artifactId>playwright</artifactId>
          <version>${playwright.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.testng</groupId>
          <artifactId>testng</artifactId>
          <version>${testng.version}</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.plugin.version}</version>
            <configuration>
              <source>${maven.compiler.source.version}</source>
              <target>${maven.compiler.target.version}</target>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven.surefire.plugin.version}</version>
            <configuration>
              <suiteXmlFiles>
                <suiteXmlFile>testng.xml</suiteXmlFile>
              </suiteXmlFiles>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    

    package com.example;
    
    import com.microsoft.playwright.*;
    import org.testng.annotations.*;
    
    public class BaseClass {
    
        // Shared between all tests in this class.
        Playwright playwright;
        Browser browser = null;
    
        // New instance for each test method.
        BrowserContext context;
        Page page;
    
        @BeforeClass
        @Parameters("browser")
        void launchBrowser(String browserName) {
    
            playwright = Playwright.create();
            BrowserType browserType = null;
    
            if (browserName.equals("chromium")) {
                browserType = playwright.chromium();
            } else if (browserName.equals("firefox")) {
                browserType = playwright.firefox();
            } else if (browserName.equals("webkit")) {
                browserType = playwright.webkit();
            }
    
            browser = browserType.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");
        }
    
        @AfterMethod
        void closeContext() {
            context.close();
        }
    
        @AfterClass
        void closeBrowser() {
            playwright.close();
        }
    }
    

    Playwright playwright;
    Browser browser = null;
    
    BrowserContext context;
    Page page;
    
    @BeforeClass
        @Parameters("browser")
        void launchBrowser(String browserName) {
    
            playwright = Playwright.create();
            BrowserType browserType = null;
    
            if (browserName.equals("chromium")) {
                browserType = playwright.chromium();
            } else if (browserName.equals("firefox")) {
                browserType = playwright.firefox();
            } else if (browserName.equals("webkit")) {
                browserType = playwright.webkit();
            }
    
            browser = browserType.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");
    }
    
    @AfterMethod
       void closeContext() {
           context.close();
    }
    
    @AfterClass
    void closeBrowser() {
          playwright.close();
    }
    

    package com.example;
    
    import org.testng.annotations.*;
    
    import static org.testng.Assert.assertEquals;
    
    public class CrossBrowserTests extends BaseClass{
    
        @Test
        void verifyPageTitle() {
            System.out.println("Page Title :" + page.title());
            assertEquals("OrangeHRM", page.title());
        }
    
        @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");
        }
        
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="Playwright test suite">
        <test name="Chrome Test">
            <parameter name="browser" value="chromium" />
            <classes>
               <class name="com.example.CrossBrowserTests"/>
        </classes>
        </test>
        <test name="firefox Test">
            <parameter name="browser" value="firefox" />
            <classes>
                <class name="com.example.CrossBrowserTests"/>
            </classes>
        </test> <!-- Test -->
    
        <test name="WebKit Test">
            <parameter name="browser" value="webkit" />
            <classes>
                <class name="com.example.CrossBrowserTests"/>
            </classes>
        </test> <!-- Test -->
    </suite>
    

    void launchBrowser(@Optional ("chromium")  String browserName) 
    

    This will run the tests in all 3 browsers as mentioned in the .xml file.

    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