Skip to main content

Page Object Model

Also known as: POM

The Page Object Model is a design pattern for UI test automation where each page (or component) of an application gets its own class encapsulating that page's locators and interactions. Tests call methods like loginPage.signIn() instead of repeating raw locator code, so a UI change only requires updating one page object, not every test that touches that page.

Without POM, locator strings end up duplicated across dozens of test files — change one button's CSS class, and you're editing every test that clicks it. POM centralizes that: the locator lives in exactly one place (the page object), and the test file only expresses intent ("sign in with these credentials"), not mechanics ("find this element, click it, wait for that one").

A typical page object exposes locators as private fields and actions as public methods. Tests are written against the methods, never against raw selectors directly — that boundary is what makes the pattern actually pay off.

The Screenplay Pattern is often positioned as POM's successor for larger suites — it models user "actors" performing "tasks" rather than pages exposing methods, which scales better when the same action (like "log in") needs to happen across many different page contexts. For small to mid-sized suites, though, POM remains the default because it's simpler to teach and reason about.

Example

class LoginPage {
  constructor(page) { this.page = page; }
  async signIn(email, password) {
    await this.page.fill('#email', email);
    await this.page.fill('#password', password);
    await this.page.click('#submit');
  }
}

// test
await new LoginPage(page).signIn('user@test.com', 'pw123');

The test expresses intent; the page object owns the locators.

Page Object Model — Definition, Example & How It's Used | QA Bash Glossary | QA Bash