Introduction

The Page Object Model (POM) is a design pattern that represents application pages as classes. It helps keep tests readable, reusable, and easier to maintain as the UI changes.

Practical Guidelines

  • Use a separate file for each page object or reusable page component.

  • Keep page objects in the repository’s page-objects/ directory.

  • Use kebab-case for page-object file names.

  • Use PascalCase for class and interface names.

  • Prefer meaningful Playwright locators over brittle selectors.

  • Encapsulate actions and assertions inside page-object methods where it improves readability.

  • Keep page objects focused on one page or component responsibility.

  • Reuse shared base functionality or interfaces when that reduces duplication.

  • Avoid mixing test-data setup and page-interaction code unnecessarily.

Example

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

export class FooPage {
  constructor(private page: Page) {}

  async goto(): Promise<void> {
    await this.page.goto('/foo');
  }

  async assertOnPage(): Promise<void> {
    await expect(this.page.getByRole('heading', { name: 'Foo Page' })).toBeVisible();
  }

  async fillValue(value: string): Promise<void> {
    await this.page.getByLabel('Foo').fill(value);
  }

  async save(): Promise<void> {
    await this.page.getByRole('button', { name: 'Save' }).click();
  }
}

Why This Helps

  • selectors stay centralized

  • tests read more like user workflows

  • UI changes are easier to isolate to one class