Playwright — Encapsulation in Page Object Model (POM)

Shiv Jirwankar
3 min readOct 18, 2024

Encapsulation in Page Object Model (POM) is all about hiding the internal implementation logic of the page exposing only the necessary actions that can be performed on that page. By following this principle we make sure that internal of page interactions are kept separate from test scripts.

Key steps for Encapsulation

  1. Private variables for locators: Define the locators or selectors as private. This ensures that they are hidden to the test files. Test should be able to interact only with methods provided by the page object.
  2. Public methods for interactions: Provide the public methods that interacts with the page elements (such as filling forms, clicking a button, etc.). This hides the implementation details of how these actions are performed by the page object.
  3. Constructor of page initiation: Initialize the page property with this parameterized constructor. This page property will be then used by locators and public methods.

Example

Let’s say you are testing a login page that has two input fields: ‘username’ and ‘password’ and a ‘login’ button. We’ll encapsulate this page’s internal details using Page Object Model (POM).

// login.ts

import { Page } from '@playwright/test';

export class LoginPage {
// Step 1: Define private fields for locators (encapsulated)
private page: Page;
private readonly usernameInput = this.page.getByTestId('username-input'); // private
private readonly passwordInput = this.page.getByTestId('password-input'); // private
private readonly loginButton = this.page.getByRole('button'); // private

// Step 2: Constructor to initialize the Page instance
constructor(page: Page) {
this.page = page;
}

// Step 3: Public method to perform login (abstracts the interaction)
public async login(username: string, password: string): Promise<void> {
await this.usernameInput.fill(username);
await this.passwordInput.fill(password);
await this.loginButton.click();
}

// Step 4: You can expose other useful methods if needed
public async getLoginErrorMessage(): Promise<string> {
return await this.page.locator('.error-message').innerText();
}
}

In this example:

  1. Locators: usernameInput, passwordInput, and loginButton are encapsulated as private fields. They cannot be accessed directly by test scripts.
  2. Methods: login() and getLoginErrorMessage() are made public and it abstracts away how the login and get error message actions are performed. Tests can directly call these methods without bothering about the internal logic.

The test file will use the page methods like this:

// loginTest.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from './loginPage';

test('User should be able to login successfully', async ({ page }) => {
const loginPage = new LoginPage(page);
await page.goto('<https://example.com/login>');
// Encapsulated login method
await loginPage.login('user1', 'password1');
// Add assertions after login if needed
await expect(page).toHaveTitle('Dashboard');
});

In this test:

  • We create an instance of the LoginPage class and invoke the login() method. The test doesn't need to know how the login happens, it just knows it can use the loginPage.login() method to perform the action.

Why Encapsulation is important in POM?

  • Maintainability: If in future, any page is getting updated, then we just need to update the relevant locator and page methods. No need to interfere the test script.
  • Reusability: Page methods can be reused across multiple tests.
  • Readability: Test scripts becomes more readable and cleaner, focused on the “what” and not the “how”.
  • Abstraction: The internal implementation details (e.g., selectors, clicking, filling inputs) are hidden from the test.

Best Practices:

  • Keep locators as private and expose only the necessary methods.
  • Group common actions like form filling, button clicking, or navigation into well-named methods.
  • Ensure that page objects do not directly expose elements to the test code.

Shiv Jirwankar
SDET

LinkedIn

--

--

Shiv Jirwankar
Shiv Jirwankar

Written by Shiv Jirwankar

Software Development Engineer in Test | An ambivert, optimistic, and karma believer | https://www.linkedin.com/in/shiv-jirwankar-45246577

Responses (1)