Testing REST APIs with Playwright in 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>org.example</groupId>
  <artifactId>Playwright_API_Demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>Playwright_API_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.15.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>

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

  </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>
        <dependencies>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</project>

 @BeforeMethod
    void setUp() {
        createPlaywright();
        createAPIRequestContext();
    }

 void createPlaywright() {
        playwright = Playwright.create();
    }

void createAPIRequestContext() {
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept", "application/json");

        request = playwright.request().newContext(new APIRequest.NewContextOptions()
                .setBaseURL("https://jsonplaceholder.typicode.com")
                .setExtraHTTPHeaders(headers));
    }

  @AfterMethod
    void tearDown() {
        if (request != null) {
            request.dispose();
        }
        if (playwright != null) {
            playwright.close();
        }
    }

 @Test
    public void getUserById() {
        APIResponse response = request.get("/posts/1");
        System.out.println("GET Response :" + response.text());
        Assert.assertEquals(response.status(), 200, "Expected 200 for GET /posts/1");

        Gson gson = new Gson();
        JsonObject jsonResponse = gson.fromJson(response.text(), JsonObject.class);
        Assert.assertEquals(jsonResponse.get("userId").getAsInt(), 1, "Expected userId=1 in response body");
        Assert.assertEquals(jsonResponse.get("id").getAsInt(), 1, "Expected id=1 in response body");
    }

POST Request

{
    "title": "architect",
    "body": "post test",
    "userId": 100
}

 @Test
    public void createUser() {
        Map<String, Object> payload = new HashMap<>();
        payload.put("title", "architect");
        payload.put("body", "post test");
        payload.put("userId", 100);

        APIResponse response = request.post("/posts", RequestOptions.create().setData(payload));
        System.out.println("POST Response :" + response.text());
        Assert.assertEquals(response.status(), 201, "Expected 201 for POST /users");

        Gson gson = new Gson();
        JsonObject body = gson.fromJson(response.text(), JsonObject.class);
        Assert.assertEquals(body.get("title").getAsString(), "architect");
        Assert.assertEquals(body.get("body").getAsString(), "post test");
        Assert.assertEquals(body.get("userId").getAsInt(), 100);
        Assert.assertNotNull(body.get("id"), "Expected id in create response");
    }

{
    "id": 1, 
    "title": "business manager",
    "body": "Implementing DataWareHouse Migration Project",
    "userId": 50
}
 @Test
    public void updateUser() {

        APIResponse response = request.get("/posts/1");
        System.out.println("GET Response before PUT Request:" + response.text());
        Assert.assertEquals(response.status(), 200, "Expected 200 for GET /posts/1");


        Map<String, Object> payload = new HashMap<>();
        payload.put("id", 1);
        payload.put("title", "business manager");
        payload.put("body", "Implementing DataWareHouse Migration Project");
        payload.put("userId", 50);

        APIResponse response1 = request.put("/posts/1", RequestOptions.create().setData(payload));
        System.out.println("PUT Response :" + response1.text());
        Assert.assertEquals(response1.status(), 200, "Expected 200 for PUT /posts/1");

        Gson gson = new Gson();
        JsonObject body = gson.fromJson(response1.text(), JsonObject.class);
        Assert.assertEquals(body.get("title").getAsString(), "business manager");
        Assert.assertEquals(body.get("body").getAsString(), "Implementing DataWareHouse Migration Project");
        Assert.assertEquals(body.get("userId").getAsInt(), 50);
        Assert.assertNotNull(body.get("id"), "Expected id in create response");

    }

   @Test
    public void deleteUser() {
        APIResponse response = request.delete("/posts/1");
        System.out.println("DELETE Response :" + response.text());
        Assert.assertEquals(response.status(), 200, "Expected 200 for DELETE /posts/1");
    }

mvn clean test

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

    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
    

    Integration of Playwright Java with TestNG

    HOME

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

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

    package com.example;
    
    import com.microsoft.playwright.*;
    import org.testng.annotations.*;
    
    import static org.testng.Assert.assertEquals;
    
    
    public class TestNG_Demo_Tests {
    
        // Shared between all tests in this class.
        Playwright playwright;
        Browser browser;
    
        // New instance for each test method.
        BrowserContext context;
        Page page;
    
        @BeforeClass
        void launchBrowser() {
            playwright = Playwright.create();
            browser = playwright.chromium().launch();
        }
    
        @BeforeMethod
        void createContextAndPage() {
            context = browser.newContext();
            page = context.newPage();
            page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
        }
    
        @Test
        void verifyPageTitle() {
            System.out.println("Page Title :" + page.title());
            assertEquals("OrangeHRM", page.title());
        }
    
        @Test
        void verifyLogin() {
            page.locator("input[name='username']").fill("Admin");
            page.locator("input[name='password']").fill("admin123");
            page.locator("button[type='submit']").click();
            String expectedValue = page.locator("//h6[contains(@class, \"oxd-topbar-header-breadcrumb-module\")]").textContent();
            assertEquals(expectedValue,"Dashboard");
        }
    
        @Test
        void verifyInvalidCredentials() {
            page.locator("input[name='username']").fill("Playwright");
            page.locator("input[name='password']").fill("admin123");
            page.locator("button[type='submit']").click();
            String expectedValue = page.locator("//p[contains(@class, \"oxd-text oxd-text--p oxd-alert-content-text\")]").textContent();
            assertEquals(expectedValue,"Invalid credentials");
        }
    
        @AfterMethod
        void closeContext() {
            context.close();
        }
    
        @AfterClass
        void closeBrowser() {
            playwright.close();
        }
    }
    
    Playwright playwright;
    Browser browser = null;
    
    BrowserContext context;
    Page page;
    

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

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

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