What Is a Page Object Model? Expert 2026 Guide

Learn what is a page object model, its core benefits for test automation, and how to implement this design pattern to create maintainable code in 2026.

what is a page object modeltest automationselenium pomplaywright testingqa testing
monito

What Is a Page Object Model? Expert 2026 Guide

what is a page object modeltest automationselenium pomplaywright testing
May 11, 2026

You change a button label, move a form field, or split one page into two steps. The product still works. Your automated tests don't.

That moment is why so many teams end up asking what is a page object model in the first place. They aren't looking for an academic pattern. They're trying to stop spending Friday afternoons fixing tests that broke because the UI changed in harmless ways.

If you've ever opened a test file and seen selectors, waits, click handlers, and assertions tangled together, you've seen the problem Page Object Model was built to solve. It gave test automation teams a way to separate user intent from page mechanics. That was a huge step forward. It still is. But it's also worth being honest about the trade-off: POM reduces chaos, yet it doesn't remove the fact that someone still has to maintain test code.

What Is a Page Object Model and Why Does It Matter

A Page Object Model, usually shortened to POM, is a test automation design pattern where each page, or meaningful part of a page, gets its own class. That class stores the locators and actions for that page. Your tests call methods on the page object instead of reaching directly into the DOM every time.

The practical value is simple. When the login button changes from one selector to another, you update one page object instead of hunting through a pile of test files.

Selenium's own documentation describes page objects as interfaces to pages in your app, which is the core idea behind the pattern. The approach became a foundational part of Selenium automation around 2011 to 2012, and a 2023 survey by Selenium community contributors found that 78% of professional automation frameworks use POM or a variant, with maintenance efforts reduced by up to 70% in large projects with frequent UI changes, according to Selenium's page object model guidance.

What POM fixes

Without POM, tests often look like this in spirit:

  • open page
  • find username input
  • type text
  • find password input
  • type text
  • find login button
  • click
  • repeat the same selectors in five other tests

That style works when you have three tests. It starts failing you when you have thirty.

The deeper problem isn't duplication alone. It's coupling. The test is trying to describe a business flow and a UI implementation at the same time. When both responsibilities live in one file, every UI tweak becomes a test rewrite.

Practical rule: Tests should describe behavior. Page objects should describe how the UI is operated.

Why it became standard

POM mattered because it gave automation teams a clean boundary:

  • Tests define intent such as logging in or checking out
  • Page objects define interaction details such as selectors, clicks, typing, and page-specific waits
  • UI changes stay localized instead of spilling across the entire suite

That separation made large Selenium suites more survivable. It also changed how teams thought about maintainability. Instead of asking, "How do we write more tests?" they started asking, "How do we write tests we can still live with six months from now?"

That's the historical importance of POM. It wasn't hype. It solved a real maintenance crisis in coded UI automation.

How the Page Object Model Organizes Your Test Code

The easiest way to understand POM is to stop thinking about test code and think about a restaurant.

Your test is the customer. The web page is the kitchen. The page object is the menu.

The customer doesn't walk into the kitchen and start touching the stove, opening drawers, and grabbing ingredients. The customer uses the menu to request actions. In the same way, a test shouldn't poke at random selectors across the page. It should call clear methods like login(), searchForProduct(), or submitOrder().

The page object as an interface

A page object gives the test a stable interface to a messy page. Inside the class, you can keep selectors, helper methods, page-specific waits, and navigation actions. Outside the class, the test just says what the user is doing.

That means a test can read more like this:

  1. Go to login page
  2. Enter credentials
  3. Submit
  4. Verify dashboard is visible

Instead of this:

  1. Find input by selector
  2. Clear it
  3. Type value
  4. Sleep
  5. Find another input
  6. Click a button
  7. Retry when the selector changes

The second version is what makes test suites brittle and unreadable.

What this separation looks like in practice

A healthy POM structure usually splits code into two layers:

Layer Responsibility
Test files Describe the scenario and assertions
Page objects Encapsulate selectors and interactions

That split helps in three ways.

  • Readability improves. A new developer can understand the flow without scanning raw selectors.
  • Reuse becomes normal. The same login method can support smoke tests, regression tests, and setup flows.
  • Maintenance gets contained. When the UI changes, the repair work usually starts in one place.

A lot of teams pair this structure with scenario planning before they write any code. If you're trying to decide what flows deserve automation, this guide to discovering test scenarios is a useful way to think about coverage before you start creating page classes.

A good page object hides implementation detail without hiding product behavior.

Where teams get confused

People sometimes turn page objects into a dumping ground for everything test-related. That's not the pattern. A page object is not your whole framework. It's an interface to a page or component.

The better mental model is narrow and boring. A checkout page object should know how to fill shipping details, apply a coupon, and place the order. It shouldn't know how to validate every business rule in your application. When page objects stay focused, tests stay readable.

The Building Blocks of a Page Object

Every page object has two basic ingredients: locators and methods.

Locators identify elements. Methods describe actions a user can take on those elements. That's the core shape whether you're writing Selenium, Playwright, or another browser automation framework.

Locators are addresses

A locator is the way your test code finds something on the page. It might target an input, a button, a heading, or a link.

In a page object, you keep those selectors together so they don't leak into every test. That's a major part of the maintainability gain. When the selector changes, the update stays local.

A simple Selenium-style page object for login might look like this:

public class LoginPage {
    WebDriver driver;

    By usernameField = By.id("username");
    By passwordField = By.id("password");
    By loginButton = By.id("loginBtn");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    public void enterUsername(String username) {
        driver.findElement(usernameField).sendKeys(username);
    }

    public void enterPassword(String password) {
        driver.findElement(passwordField).sendKeys(password);
    }

    public void clickLogin() {
        driver.findElement(loginButton).click();
    }

    public void login(String username, String password) {
        enterUsername(username);
        enterPassword(password);
        clickLogin();
    }
}

This is plain, explicit POM. Nothing fancy. It works because it centralizes the page mechanics.

Methods are the user-facing API

The methods are where a page object becomes useful. They should reflect actions a user or test cares about.

Good method names are specific:

  • enterUsername
  • clickLogin
  • applyCoupon
  • selectShippingMethod

Weak method names usually expose raw implementation detail or become too generic.

A Playwright-style version often feels cleaner because locators are first-class objects:

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

export class LoginPage {
  readonly page: Page;
  readonly usernameField: Locator;
  readonly passwordField: Locator;
  readonly loginButton: Locator;

  constructor(page: Page) {
    this.page = page;
    this.usernameField = page.locator('#username');
    this.passwordField = page.locator('#password');
    this.loginButton = page.locator('#loginBtn');
  }

  async goto() {
    await this.page.goto('/login');
  }

  async login(username: string, password: string) {
    await this.usernameField.fill(username);
    await this.passwordField.fill(password);
    await this.loginButton.click();
  }
}

This version still follows POM. It just uses a framework with stronger built-in locator behavior.

Where Page Factory fits

Page Factory is a Selenium-specific enhancement to POM. Instead of manually calling findElement in multiple places, it uses annotations like @FindBy and initializes elements through initElements().

According to BrowserStack's overview of Page Factory and POM, Page Factory can improve performance by 30% to 50% in page-heavy suites, and a 2024 LambdaTest survey found that 62% of QA engineers prefer it for readability, with a 40% reduction in boilerplate code compared to manual initialization.

A Page Factory example looks like this:

public class LoginPage {
    WebDriver driver;

    @FindBy(id = "username")
    WebElement usernameField;

    @FindBy(id = "password")
    WebElement passwordField;

    @FindBy(id = "loginBtn")
    WebElement loginButton;

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public void login(String username, String password) {
        usernameField.sendKeys(username);
        passwordField.sendKeys(password);
        loginButton.click();
    }
}

Page Factory reduces boilerplate. It doesn't change the core idea. You still own the page class, the selectors, and the maintenance.

POM Benefits and Common Mistakes to Avoid

POM earns its reputation when a product team ships UI changes every week and the test suite doesn't explode. That's where the pattern shines.

The biggest win is maintenance. Skyvern's guide to page object model notes that POM can reduce QA maintenance effort from 40% of total work to 10%, and that modern Playwright-style auto-wait locators can cut explicit waits by up to 80% compared to traditional Selenium setups. Those numbers match what many practitioners see in real projects: cleaner abstractions, less duplicated selector work, fewer panic edits across dozens of tests.

What works well

When teams use POM well, a few benefits show up quickly:

  • Reuse across many tests. One login page object can support setup for multiple suites.
  • Readable test flow. Business steps stand out because low-level interactions move out of the test file.
  • Local fixes. A selector update often means changing one page object instead of many scenarios.
  • Cleaner onboarding. New contributors can understand tests without reverse-engineering every locator.

This is why POM lasted. It solves a real engineering problem instead of just making code look neat.

What usually goes wrong

Most failed POM implementations don't fail because the idea is bad. They fail because the abstraction gets abused.

Common mistakes include:

  • God objects
    One class grows to represent an entire application area instead of one page or one coherent component. It becomes hard to change and harder to trust.

  • Assertions inside page objects
    Page objects should interact with the UI. Tests should assert business outcomes. Mixing both makes reuse painful.

  • Low-value wrapper methods
    Methods like clickButton1() or setField2() tell you nothing. A page object should express intent, not just rename every DOM action.

  • Caching unstable elements
    If the DOM refreshes often, stale references will bite you. Dynamic pages need careful locator strategy and framework-aware waiting.

Keep page objects close to user actions and far away from test assertions.

The honest trade-off

POM reduces maintenance. It does not eliminate maintenance.

You still need engineers to design page classes well, review changes, clean up selector drift, and refactor as the app evolves. That's one reason some teams are exploring broader shifts in automation architecture, including systems built around decentralized AI agents, where execution can become more adaptive and less tied to brittle, hand-maintained test code.

If you're building a coded automation stack today, POM is still one of the best ways to stay organized. But if your team is tiny, it's fair to ask a harder question: are you solving test maintenance, or are you just reorganizing it? A good checklist for making that call is this set of automated testing best practices.

Is the Page Object Model Still the Best Choice

Sometimes yes. Often no.

POM is still a strong choice when your team already writes and maintains automation code, especially in Selenium or Playwright. It gives structure to a coded framework and makes UI automation less chaotic. But it isn't automatically the best option for every product team, especially small teams that don't want test code to become another software project.

The real alternatives

At a high level, teams usually end up in one of four camps:

Approach Required Skill Maintenance Effort Best For
Ad hoc test scripts without a pattern Basic scripting skill High as the suite grows Very small, temporary test coverage
Page Object Model Solid automation engineering skill Moderate, if designed well Teams building and owning coded UI suites
Modern coded frameworks with stronger locator models Solid automation engineering skill Lower than older Selenium setups, but still ongoing Teams that want code-level control with better ergonomics
Code-free AI testing tools Low to moderate product and testing judgment Lower because the team doesn't manage page classes and selectors directly Founders, small teams, and fast-moving products

The first option breaks down fast. Raw scripts are easy to start and painful to scale.

POM is the middle ground. It adds discipline, but discipline has a cost. Someone has to create the abstractions, keep them healthy, and decide when the page model no longer matches the product.

Where POM still wins

Choose POM when:

  • your team already knows Selenium or Playwright
  • you need code review and framework-level control
  • the app has stable enough flows to justify maintaining page classes
  • you want explicit ownership over selectors and interactions

This is especially true in larger organizations with dedicated QA or SDET support. There, the framework itself is a product.

Where it stops being the best fit

POM becomes less attractive when the people writing product code are also expected to maintain the automation layer. For a founder or a team of a few developers, page objects can feel like responsible engineering right up until they become a second app to maintain.

That tension is why code-free AI testing tools are getting attention. POM separates test logic from UI implementation. AI-driven approaches go one step further and separate user intent from the coded test layer itself. Instead of writing page classes, you describe the behavior you want checked and let the system execute it through a browser.

The question isn't whether POM is good. It's whether your team wants to own the codebase that comes with it.

For teams that love code and need precision, POM still makes sense. For teams that just need reliable coverage without building a test framework, it may no longer be the default answer.

Choosing the Right Testing Strategy for Your Team

The right answer depends less on doctrine and more on team shape.

If you have dedicated automation engineers, a stable product surface, and the appetite to maintain a framework, Page Object Model is still a strong engineering choice. It gives structure to browser automation and keeps a growing suite from collapsing into copy-pasted selectors.

If you're a small SaaS team, solo founder, or product-minded dev shop, the calculation changes. Every hour spent refining page objects is an hour you're not shipping features, fixing customer issues, or improving onboarding. That's why many small teams don't really have a tooling problem. They have a maintenance budget problem.

A simple way to decide

Ask three questions:

  1. Who will maintain the test suite six months from now?
    If the answer is "probably the same developers already stretched thin," be careful with coded frameworks.

  2. How often does the UI change?
    Frequent interface changes make traditional locator-driven automation more expensive to own.

  3. Do you need a framework, or do you need confidence before release?
    Those aren't the same thing.

If you're evaluating testing strategy as part of a broader delivery process, Tekk.coach's breakdown of process models is a useful reminder that tooling choices should match how your team builds software, not how a textbook says teams should work.

A lot of small teams benefit more from lightweight, repeatable testing inside delivery workflows than from building a large automation architecture. This is also why it helps to think about testing in the context of CI, release rhythm, and ownership, not just framework elegance. This guide to test automation in DevOps is a practical place to start.

POM is important. It changed automated UI testing for the better. But for many teams, the next evolution isn't a better page object. It's removing the need to write one.


If you want the confidence of structured web app testing without maintaining Selenium or Playwright scripts, try Monito. You describe what to test in plain English, the AI agent runs it in a real browser, and you get bug reports with screenshots, logs, and session data. It's a practical fit for founders and small teams that need more coverage without taking on a QA codebase.

All Posts