24. Enterprise Page Object Model & Component Architecture

Why Page Object Model (POM)?

Without POM, when a login button selector changes, you must update 50 different test files. With POM: - Single Source of Truth: Locators and UI actions live in dedicated class files. - Readable Tests: Tests read like plain-English business workflows. - Maintainability: UI changes require updating only one method or locator.

---

Professional POM Architecture

// pages/BasePage.ts
import { Page, Locator } from "@playwright/test";

export abstract class BasePage {
constructor(protected readonly page: Page) {}

public async navigateTo(path: string): Promise<void> {
await this.page.goto(path);
}

public async waitForPageLoad(): Promise<void> {
await this.page.waitForLoadState("domcontentloaded");
}
}

// pages/LoginPage.ts
import { Page, Locator, expect } from "@playwright/test";
import { BasePage } from "./BasePage";

export class LoginPage extends BasePage {
// 1. Declare Locators as readonly properties
private readonly usernameInput: Locator;
private readonly passwordInput: Locator;
private readonly loginButton: Locator;
private readonly errorMessage: Locator;

constructor(page: Page) {
super(page);
this.usernameInput = page.getByLabel("Username");
this.passwordInput = page.getByLabel("Password");
this.loginButton = page.getByRole("button", { name: "Sign In" });
this.errorMessage = page.getByRole("alert");
}

// 2. High-level business actions
public async login(user: string, pass: string): Promise<void> {
await this.usernameInput.fill(user);
await this.passwordInput.fill(pass);
await this.loginButton.click();
}

// 3. Status checks
public async expectErrorMessage(message: string): Promise<void> {
await expect(this.errorMessage).toContainText(message);
}
}

---

Good POM vs Bad POM

- Good POM: Exposes user-intent methods (login(user, pass), addItemToCart(item)). Locators are private. - Bad POM: Exposes raw locators or exposes tiny methods for every single click (clickUsername(), clickPassword()).

Task

  • Implement CartComponent:
  • 1. Declare a private field itemCount initialized to 0.
  • 2. Implement public method addItem() that increments itemCount.
  • 3. Implement public method getItemCount() that returns itemCount.
πŸ’‘Common doubts
Did you like the problem?
Lesson 24 of 36
TypeScript
Loading code editor…
Next