Implementation of Page Object Model in Playwright

  

What is Page Object Model (POM)?

Page Object Model (POM) is a design pattern in test automation where each web page (or component) is represented by a corresponding Java class containing all the locators and methods that interact with the page.
  • It is used to create a separate class or object repository for each page of the application under test.
  • Instead of writing locators and actions directly inside the test scripts, you define them in Page Classes.
  • Each class contains: Locators (elements on that page), Methods (actions or business logic you can perform on that page)

Page Object Model in Playwright

  • Each webpage of the application is represented as a class.
  • Inside that class: Define locators for elements on the page (e.g., username field, login button). Define methods to interact with those elements (e.g., enterUsername(), clickLogin()).
Then in the test scripts:
  • You just call the methods from the Page Object class instead of repeating locators and actions.

Example:
  • Create LoginPage class → define locators & methods.
  • Create HomePage class → define locators & methods.
  • In the test file, call loginPage.login("user","pass") and verify HomePage actions.


Why Use POM in Playwright?

  • Playwright supports parallel execution and complex applications → POM keeps tests structured.
  • Large projects with many pages and workflows become easier to manage.
  • Helps teams follow clean automation architecture, where any change in UI affects only Page Object files, not every test.

Benefits of Page Object Model
  • Reusability: Common actions can be reused across multiple tests.
  • Maintainability: If a locator changes, you update it in one place (Page Class), not across all tests.
  • Readability: Test scripts become more readable since they call methods like loginPage.enterUsername() instead of handling locators directly.
  • Separation of Concerns: Test logic and page structure are kept separate.
















Website to be automated: 

https://opensource-demo.orangehrmlive.com/web/index.php/auth/login






1. Maven Dependencies

Added dependencies of Cucumber, TestNG and Playwright

<dependencies>
    <!-- Playwright -->
    <dependency>
        <groupId>com.microsoft.playwright</groupId>
        <artifactId>playwright</artifactId>
        <version>1.44.0</version>
    </dependency>

    <!-- Cucumber -->
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-java</artifactId>
        <version>7.16.1</version>
    </dependency>
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-testng</artifactId>
        <version>7.16.1</version>
    </dependency>

    <!-- TestNG -->
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>7.9.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>


2. Feature File (login.feature)

Below is the feature file contains login feature. Under feature a successful login scenario steps are defined which are written with the help of gherkins keywords.

Feature: Login Feature

  Scenario: Successful Login
    Given User is on login page
    When User enters username "admin" and password "admin123"
    Then User should see the dashboard page


3. PlaywrightFactory.java (Utility to manage Playwright setup)

Below is the PlaywrightFactory class which is basically a utility class implemented in Playwright Java and contains Playwright, Browser, BrowserContext and Page objects. It conatains methods to initialize and close browser and to get Page object.


package 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() {
        browser.close();
        playwright.close();
    }
}


4. LoginPage.java (Page Object Model)

Below is the Page class named as LoginPage.java. In this class there are locators of username field, password field, login button and dashboard text. It contains different methods to enter username, password, click submit button and verify text on dashboard.


package pages;

import com.microsoft.playwright.Page;

public class LoginPage {
    private Page page;

    // Locators
    private String usernameField = "#username";
    private String passwordField = "#password";
    private String loginButton = "#button[type='submit']";
    private String dashboardText = "h6[class='oxd-text oxd-text--h6 oxd-topbar-header-breadcrumb-module']";

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

    public void navigateToLoginPage() {
        page.navigate("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login");
    }

    public void enterUsername(String username) {
        page.fill(usernameField, username);
    }

    public void enterPassword(String password) {
        page.fill(passwordField, password);
    }

    public void clickLogin() {
        page.click(loginButton);
    }

    public boolean isDashboardVisible() {
        return page.isVisible(dashboardText);
    }
}


5. LoginSteps.java (Step Definitions)

Below is the LoginSteps.java class which is basically a step definition file for login.feature, Here all steps which are defined in feature files are implemented by using Java. Annotations are used for respective gherkins keywords like @Given, @When, etc.

package stepdefinitions;

import com.microsoft.playwright.Page;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.*;
import pages.LoginPage;
import utils.PlaywrightFactory;
import org.testng.Assert;

public class LoginSteps {
    private Page page;
    private LoginPage loginPage;

    @Before
    public void setup() {
        PlaywrightFactory.initBrowser();
        page = PlaywrightFactory.getPage();
        loginPage = new LoginPage(page);
    }

    @Given("User is on login page")
    public void user_is_on_login_page() {
        loginPage.navigateToLoginPage();
    }

    @When("User enters username {string} and password {string}")
    public void user_enters_username_and_password(String username, String password) {
        loginPage.enterUsername(username);
        loginPage.enterPassword(password);
        loginPage.clickLogin();
    }

    @Then("User should see the dashboard page")
    public void user_should_see_the_dashboard_page() {
        Assert.assertTrue(loginPage.isDashboardVisible(), "Dashboard");
    }

    @After
    public void tearDown() {
        PlaywrightFactory.closeBrowser();
    }
}


6. TestRunner.java (TestNG + Cucumber Runner)

TestRunner class is used to execute tests written in feature files and implemented in step definition files. Here path of feature file is given by 'features' keyword and path of step definition by 'glue' keyword. All these things are implemented under @CucumberOptions annotation. This TestRunner class is implemented by Cucumber and TestNG.


package testrunners;

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

@CucumberOptions(
    features = "src/test/java/features",
    glue = {"stepdefinitions"},
    plugin = {"pretty", "html:target/cucumber-report.html"},
    monochrome = true
)
public class TestRunner extends AbstractTestNGCucumberTests {
}


7. TestNG.XML (Optional - if running via TestNG suite)

TestNG.xml is optional file which contains TestRunner class path represented in class tag. We can execute TestRunner class by TestNG.xml also.

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Cucumber with TestNG">
    <test name="CucumberTests">
        <classes>
            <class name="testrunners.TestRunner" />
        </classes>
    </test>
</suite>


Suggested Posts:

1. Handle IFrames in Playwright
2. Automate Login Page in Playwright
3. Comma Selectors in Playwright
4. Handle Alerts in Playwright
5. How to Show Visible Elements in Playwright

Comma Selectors in Playwright

 

In Playwright Javacomma selectors refer to compound selectors that use commas , to combine multiple selectors, allowing you to target multiple elements at once — similar to how they work in CSS.


How Comma Selectors Work in Playwright

(1) Multiple Elements in One Locator

  • Instead of writing separate locators for each element type, you can combine them using commas.
  • This is useful when the elements share similar behavior but have different identifiers.

(2) Playwright Behavior

  • Playwright evaluates each selector in the group, then merges the results into a single collection of matched elements.
  • You can then perform actions (click, count, assert visibility, etc.) on those matched elements.

(3) Scenarios Where Useful

  • Different button styles: If "Submit" might be a <button> in one place but an <input> in another, you can write one combined selector.
  • Dynamic UIs: When the element can appear in multiple formats depending on conditions (e.g., mobile vs desktop view).
  • Bulk operations: Selecting multiple types of similar items (like all headings h1, h2, h3).


Key Points to Remember
  • Comma selectors follow CSS selector rules since Playwright supports CSS selectors.
  • They help reduce duplication in locators.
  • But be careful: too many comma selectors can make locators harder to maintain, so use them when elements are truly interchangeable.
























What Are Comma Selectors?

comma selector allows you to select multiple elements that match any of the selectors separated by a comma.

Syntax:

Locator locator = page.locator("selector1, selector2, selector3");


Website to be automated: https://www.google.com/













Java Playwright Code:


import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;

public class CommaSelectorsExample {
	
	public static void main(String[] args) {
		
	// this code will click Gmail or if instead of Gmail GoogleMail is present like or condition
	Playwright playwright = Playwright.create();
	Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
	Page p1 = browser.newPage();
	p1.navigate("https://www.google.co.in");
	p1.locator("a:has-text('Gmail'),a:has-text('GoogleMail') ").click();
	
	//For two links comma seperated selector code is there
	Page p2 = browser.newPage();
	p2.navigate("https://www.google.co.in");
	Locator lc = p2.locator("a:has-text('Gmail'),a:has-text('Images') ");
	System.out.println(lc.count());
	
	//click on Gmail by using xpath
	Page p3 = browser.newPage();
	p2.navigate("https://www.google.co.in");
	Locator gmailLocator = p2.locator("//a[text()='Gmail'] | //a[text()='GooleMail'] ");
	System.out.println(gmailLocator.textContent());
	gmailLocator.click();
	
	browser.close();
	playwright.close();

}
}


Code explanation:

(a) Navigate to the website by page.navigate()
(b) Locator will locate web element either by first or second locator separated by comma or by both, if both are able to find web element.


(c) In next steps also, we are finding web elements by appropriate locator, printing the count and text of the locators.


Important Points:
  • Comma selectors are useful when you want to interact with multiple possible matching elements.
  • Playwright executes them like CSS, meaning it selects all matching elements.