Next-Gen App & Browser
Testing Cloud

Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Next-Gen App & Browser Testing Cloud

What Is Page Object Model (POM) Design Pattern

Understand the Page Object Model in detail, its purpose, structure, and how Page Factory helps build cleaner, maintainable, and scalable automated test suites.

Published on: October 12, 2025

  • Share:

In automation testing, keeping test scripts reliable and easy to maintain is often challenging. Test scripts can become brittle, redundant code can build up, and adapting to frequent UI changes can slow down development. This is where the Page Object Model (POM) solves these issues. It organizes web elements and actions into separate classes, creating a clear separation between test logic and UI structure. This approach reduces duplicate code, makes tests easier to maintain, and lets you update them quickly whenever the UI changes.

Overview

The Page Object Model is a test automation design pattern that organizes pages or components into classes, encapsulating locators and actions for readable, maintainable, resilient tests.

Why Use Page Object Model?

Adopting the Page Object Model provides several practical advantages for test automation, delivering stability, clarity, and maintainability through well-structured code. Some of the key benefits include:

  • Code Reusability and Scalability: Page object classes allow reusable methods for actions, reducing redundancy across tests and scaling automation suite efficiently for future changes.
  • Simplified Test Maintenance: Encapsulating locators and actions in page classes allows updates in one place, reducing maintenance effort and preventing broken tests during UI changes.
  • Improved Code Readability: Separating page classes from test logic ensures tests focus on validation, making them understandable, clear, and easier to maintain over time.
  • Reduced Code Duplication: Centralizing web elements and actions enforces DRY principles, eliminates repetitive code, prevents errors, and ensures consistent, reliable behavior across all automated tests.
  • Better Abstraction and Encapsulation: POM hides UI interaction details behind methods, enabling tests to focus on performing actions instead of knowing implementation mechanics internally.

How to Use Page Object Model?

Implementing the Page Object Model requires a structured, practical approach that keeps your automation code clean, maintainable, and scalable. Here are the steps to use POM:

  • Create Page Classes: Define separate classes for each page, keeping locators private and providing methods to perform actions while ensuring reusability across tests.
  • Use Methods in Tests: Always call page methods rather than WebDriver commands directly, keeping tests readable, maintainable, and independent of the underlying UI implementation.
  • Return Page Objects: When navigation occurs, return the corresponding page object from methods, enabling smooth method chaining and streamlined test workflows across multiple pages.
  • Implement Utilities: Include drivers, configuration readers, explicit waits, and reusable helpers to enhance framework maintainability, robustness, and stability across diverse testing scenarios.
  • Maintain Scalability: Follow consistent naming conventions, avoid overloaded classes, and keep methods focused, ensuring the automation framework remains scalable and easy to extend over time.

What Is Page Object Model?

Page Object Model in automation testing is a design pattern where each page is a class with locators and methods, separating UI from test logic to improve readability, reuse, and maintenance.

In POM:

  • Each page of your software application is represented by a class called a page object.
  • This page object contains:
    • Locator: A way to find an element on a web page, like a button, input field, or link. It tells the test exactly where to click or type. Examples include ID, Name, CSS Selector, or XPath.
    • Method / Action: A function inside a page object that performs a user interaction, like login(), clickSubmit(), or enterUsername(). Tests call these methods instead of directly interacting with elements.
    • Test Script: The code that runs a test scenario, like logging in or adding an item to the cart. It uses page objects instead of finding elements directly.

You can also check out this video tutorial on Page Object Model by Koushik Chatterjee. He is a Founder of LetCode and a Senior Software Test Automation Engineer. Koushik brings close to 10 years of experience in test automation, specializing in building reliable frameworks and driving quality at scale.

Why Need a Page Object Model?

POM centralizes page actions, hides UI details, and reduces duplicate code. It also improves readability, eases maintenance, and enables reusable, scalable, and well-structured test scripts.

Benefits:

  • Code Reusability and Scalability: POM allows you to create reusable methods for page actions in the page object classes. This approach helps reuse the same code across multiple tests. It improves code reusability and makes the test scripts more scalable as the test automation suite grows.
  • Test Maintenance becomes Easy: When there is a change in the UI of the software application, updating the locators, actions, and tests can be a tedious task. With POM, the locators and interaction methods are included in different page object classes. This lets you make the necessary changes to the respective page object class, making test maintenance easier.
  • Improves Code Readability: By creating separate page object classes for each web page, the test logic is kept separate from the locators and interaction methods. This keeps tests clean and focused on validations, improving readability. It also allows you to easily understand the functionality under test without getting confused by the technical details of the web page.
  • Reduces Code Duplication: With the Page Object Model, the web elements and the web page actions are centralized in the page object classes. This encourages the Don’t Repeat Yourself (DRY) principle, making tests easier to maintain and less prone to errors.
  • Better Test Abstraction and Encapsulation: In POM, the details of UI interactions are hidden behind the easy-to-use methods, allowing test abstraction. This makes the tests focus on the actions to perform rather than how they’re done.
Note

Note: Run automated tests across over 3000 real environments. Try LambdaTest Now!

What Are the Core Concepts of the Page Object Model?

In the Page Object Model, an organized approach is followed, built around core components including page classes, locators, and methods. These core concepts are important for ensuring that the test automation scripts remain well-structured, maintainable, and easy to manage.

Page Classes

In POM, a dedicated class is created for every web page. This dedicated class contains all the page objects for the web elements on the page, including buttons, text boxes, checkboxes, links, etc. It also has the action methods, which are used for interacting with these web elements on the page.

By using page classes, POM helps keep test scripts clean, organized, and improves their maintainability. For example, if you are testing the Registration Page of a web application, the locators related to the respective page will be updated in the RegistrationPage class. Similarly, for the login page, a new class, LoginPage, will be created to store its web elements.

public class RegistrationPage {
    WebDriver driver;
    private By name = By.id("name"), email = By.id("email"), pass = By.id("password"),
                 terms = By.id("terms"), register = By.id("registerBtn");

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

    public void registerUser(String n, String e, String p) {
        driver.findElement(name).sendKeys(n);
        driver.findElement(email).sendKeys(e);
        driver.findElement(pass).sendKeys(p);
        driver.findElement(terms).click();
        driver.findElement(register).click();
    }
}

// Test
RegistrationPage reg = new RegistrationPage(driver);
reg.registerUser("John Doe", "john@example.com", "Password123");

Locators

Locators specify the way web elements are identified on a page. For example, automation testing tools like Selenium offer different locator strategies to locate a WebElement. Locators in Selenium WebDriver include ID, Name, CSS Selector, XPath, etc. With POM’s centralized approach, it's easier to update locators whenever the UI changes.

private By emailField = By.id("email");
private By passwordField = By.id("password");
private By loginButton = By.id("loginBtn");

Locators can be stored as constant variables within the page classes, so if a locator changes, only the corresponding variable needs to be updated without altering the core test scripts. Alternatively, locators can be maintained in external files such as JSON, YAML, or Properties files.

Methods

Methods in POM are designed to interact with the web elements and perform the required actions. The automation tests can call these methods, enhancing the code readability and reusability.

For example, a performLogin() method can be added to the page object class to simulate a user logging in by entering the email and password and clicking the login button. This method can then be called directly in the test, keeping the test script concise and easy to read.

public class LoginPage {
    WebDriver driver;
    private By email = By.id("email");
    private By password = By.id("password");
    private By loginBtn = By.id("loginBtn");

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

    // Method to perform login
    public void performLogin(String user, String pass) {
        driver.findElement(email).sendKeys(user);
        driver.findElement(password).sendKeys(pass);
        driver.findElement(loginBtn).click();
    }
}

// Test script
LoginPage login = new LoginPage(driver);
login.performLogin("user@example.com", "password123");

How to Implement Page Object Model?

You can implement Page Object Model by creating separate classes for each page, encapsulating locators and methods, and using these objects in test scripts to improve maintainability and readability.

Let’s implement the Page Object Model using testing tools like Selenium. If you are new to Selenium, refer to this step-by-step Selenium tutorial.

Setup and Configuration

Create a new Maven Project and add the following dependencies for Selenium WebDriver and TestNG in the pom.xml file.

<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.35.0</version>
</dependency>
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.11.0</version>
    <scope>test</scope>
</dependency>

We’ll run the tests on the latest version of the Chrome browser on the local machine. Create a BaseTest.java class to separate the browser configuration from the tests.

public class BaseTest {

   protected WebDriver driver;

   @BeforeClass
   public void setup () {
       driver = new ChromeDriver ();
       this.driver.manage ()
           .timeouts ()
           .implicitlyWait (Duration.ofSeconds (10));
   }

}

The setup() method will instantiate a new WebDriver session on the local machine. The Selenium Manager will handle driver and browser management by downloading the required ChromeDriver and browser at run time.

@AfterClass
   public void tearDown () {
       this.driver.quit ();
   }
}

The tearDown() method closes the driver session cleanly once all the tests have finished running.

Implementation

We will implement POM for both registration and login test scenarios in the LambdaTest eCommerce Playground. This clearly shows how shared pages and elements can be reused efficiently. The real value of POM appears when multiple workflows use the same parts of the web application.

Test Scenario 1:

  • Navigate to the Register Account page of the LambdaTest eCommerce Playground website.
  • Register as a new user.
  • Verify the user is registered successfully by asserting the message “Your Account Has Been Created!”.

Implementation:

Create a LambdaTestECommerceTests class to write the automation scripts for the test scenario. This class extends the BaseTest.java class to enable code reuse and promote modularity.

Add a testRegisterUser() method that carries out the test scenario for user registration.

public class LambdaTestECommerceTests extends BaseTest {

   private static final String EMAIL    = "johndoe77@email.com";
   private static final String PASSWORD = "Password@321";

   @Test
   public void testRegisterUser () {
       this.driver.navigate ()
           .to ("https://ecommerce-playground.lambdatest.io/index.php?route=account/register");

       final RegistrationPage registrationPage = new RegistrationPage (this.driver);
       final RegistrationSuccessPage registrationSuccessPage = registrationPage.registerUser ("John", "Doe", EMAIL,
           "00974633", PASSWORD);

       assertEquals (registrationSuccessPage.getSuccessMessage (), "Your Account Has Been Created!");
   }

LambdaTest Page Object Model GitHub Repository

The Page Object Model has been used to enhance code reusability, readability, and easy maintenance.

public class BasePage {
   protected WebDriver driver;
   public BasePage (final WebDriver driver) {
       this.driver = driver;
   }
}

The BasePage class is defined to store the common page objects throughout the website, allowing them to be reused. It is a parent class in the Page Object Model and stores the WebDriver instance.

The constructor of the BasePage class accepts a WebDriver object and assigns it to the class’s driver, so all the page classes that extend BasePage can use the same driver, avoiding duplicate code and easily sharing the browser instance across different page objects.

The RegistrationPage class is created as a page object class for the registration page, holding all the respective page objects.

public class RegistrationPage extends BasePage {
   private final By firstNameField  = By.id ("input-firstname");
   private final By lastNameField   = By.id ("input-lastname");
   private final By emailField      = By.id ("input-email");
   private final By telephoneField  = By.id ("input-telephone");
   private final By passwordField   = By.id ("input-password");
   private final By confirmPassword = By.id ("input-confirm");
   private final By agreePolicy     = By.id ("input-agree");
   private final By continueBtn     = By.cssSelector ("input.btn-primary");

   public RegistrationPage (final WebDriver driver) {
       super (driver);
   }

   public RegistrationSuccessPage registerUser (final String firstName, final String lastName, final String emailId,
       final String telephoneNumber, final String password) {
       this.driver.findElement (this.firstNameField)
           .sendKeys (firstName);
       this.driver.findElement (this.lastNameField)
           .sendKeys (lastName);
       this.driver.findElement (this.emailField)
           .sendKeys (emailId);
       this.driver.findElement (this.telephoneField)
           .sendKeys (telephoneNumber);
       this.driver.findElement (this.passwordField)
           .sendKeys (password);
       this.driver.findElement (this.confirmPassword)
           .sendKeys (password);
       final WebElement agreePolicyCheckBox = this.driver.findElement (this.agreePolicy);
       final Actions actions = new Actions (this.driver);
       actions.moveToElement (agreePolicyCheckBox)
           .click ()
           .build ()
           .perform ();
       this.driver.findElement (this.continueBtn)
           .click ();
       return new RegistrationSuccessPage (this.driver);
   }
}

The locators are defined as constants for the fields, allowing them to be reused across the codebase and preventing duplication.

The registerUser() method performs the interaction with the fields on the page and simulates the user registration action. Finally, it returns a new instance of the RegistrationSuccessPage class, which displays the registration success message.

public class RegistrationSuccessPage extends BasePage {

   private final By        successMessage = By.cssSelector ("#content h1");

   public RegistrationSuccessPage (final WebDriver driver) {
       super (driver);
   }

   public String getSuccessMessage () {
       return this.driver.findElement (this.successMessage)
           .getText ();
   }
}

The RegistrationSuccessPage class follows the same pattern, separating the locators and methods.

Test Scenario 2:

  • Navigate to the Account Login page of the LambdaTest eCommerce Playground website.
  • Log in with the registered email address and password.
  • Verify that the user is logged in successfully.

Implementation:

Add a new testLogin() method in the LambdaTestECommerceTests class. This method implements the test scenario for user login.

@Test
public void testLogin () {
   this.driver.navigate ()
       .to ("https://ecommerce-playground.lambdatest.io/index.php?route=account/login");

   final LoginPage loginPage = new LoginPage (this.driver);
   final MyAccountPage myAccountPage = loginPage.performLogin (EMAIL, PASSWORD);
   assertEquals (myAccountPage.getPageTitle (), "My Account");
}

The LoginPage class is created as the page object class for the Account Login page and holds its locators and interaction methods.

public class LoginPage extends BasePage {

   private final By emailField    = By.id ("input-email");
   private final By passwordField = By.id ("input-password");
   private final By loginButton   = By.cssSelector ("input[type="submit"]");

   public LoginPage (final WebDriver driver) {
       super (driver);
   }

   public MyAccountPage performLogin (final String email, final String password) {
       this.driver.findElement (this.emailField)
           .clear ();
       this.driver.findElement (this.emailField)
           .sendKeys (email);
       this.driver.findElement (this.passwordField)
           .clear ();
       this.driver.findElement (this.passwordField)
           .sendKeys (password);
       this.driver.findElement (this.loginButton)
           .click ();
       return new MyAccountPage (this.driver);
   }
}

The performLogin() method accepts the email and password as parameters, performs necessary actions for user login, and returns a new instance of the My Account page.

Likewise, the MyAccountPage class contains all the page objects of the My Account page.

public class MyAccountPage extends BasePage {

   private final By pageTitle = By.cssSelector ("#content h2");

   public MyAccountPage (final WebDriver driver) {
       super (driver);
   }

   public String getPageTitle () {
       return this.driver.findElement (this.pageTitle)
           .getText ();
   }
}

We need the title of this page to verify that the user has logged in successfully. The getPageTitle() method returns the title of the page. This method is used in the test to check that the correct page title, “My Account”, is displayed.

Test Execution:

Create a new testng.xml file named “testng-pageobjectmodel.xml“ to run the tests. The tests will be executed on the latest version of the Chrome browser.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="LambdaTest ECommerce Website Test Suite">
   <test name="LambdaTest ECommerce Playground - Registration Test">
   <classes>
       <class name="io.github.mfaisalkhatri.pageobjectmodeldemo.tests.LambdaTestECommerceTests">
           <methods>
               <include name="testRegisterUser"/>
           </methods>
       </class>
   </classes>
   </test>
   <test name="LambdaTest ECommerce Playground - Login Test">
       <classes>
           <class name="io.github.mfaisalkhatri.pageobjectmodeldemo.tests.LambdaTestECommerceTests">
               <methods>
                   <include name="testLogin"/>
               </methods>
           </class>
       </classes>
   </test>
</suite>

Run the following command to execute the tests:

mvn clean install -Dsuite-xml=test-suites/testng-pageobjectmodel.xml

The following screenshot from IntelliJ IDE shows that the tests were executed successfully:Page Object Model Local Test Execution

How to Run POM Structured Tests At Scale With LambdaTest?

LambdaTest is a cloud-based testing platform that enables cross-browser and cross-platform testing on multiple operating systems and devices. It eliminates the need for local infrastructure, allows tests to run in parallel at scale, and ensures faster, more reliable validation across diverse environments.

To get started, you can check out this documentation on Selenium testing with LambdaTest.

...

To run the tests on the LambdaTest platform, we need to define specific capabilities for the platform, browser, and browser versions.

To simplify this, we can use the LambdaTest Automation Capabilities Generator. Next, create a BaseTest.java class file to hold all the configuration details.

public class BaseTest {
   protected              RemoteWebDriver driver;
   private static final String          LT_USERNAME   = System.getenv ("LT_USERNAME");
   private static final String          LT_ACCESS_KEY = System.getenv ("LT_ACCESS_KEY");
   private static final String          GRID_URL      = "@hub.lambdatest.com/wd/hub";
   

The LambdaTest cloud grid can be connected using the LambdaTest Username, Access Key, and Grid URL. The Username and Access Key can be found in the Account Settings under Password & Security.

Once we have these, we can write the test script to handle different browsers and start their respective sessions.

@BeforeClass
public void setup () {
   try {
       this.driver = new RemoteWebDriver (new URL ("https://" + LT_USERNAME + ":" + LT_ACCESS_KEY + GRID_URL),
           getChromeOptions ());

   } catch (final MalformedURLException e) {
       System.out.println ("Could not start the remote session on LambdaTest cloud grid");
   }
   this.driver.manage ()
       .timeouts ()
       .implicitlyWait (Duration.ofSeconds (10));
}

The setup() method will instantiate a new RemoteWebDriver session on the LambdaTest cloud grid. Using the configurations set in the getChromeOptions() method, it will start a new Chrome browser session.

private ChromeOptions getChromeOptions () {
   final var browserOptions = new ChromeOptions ();
   browserOptions.setPlatformName ("Windows 10");
   browserOptions.setBrowserVersion ("latest");
   final HashMap<String, Object> ltOptions = new HashMap<> ();
   ltOptions.put ("project", "POM demo With Selenium");
   ltOptions.put ("build", "LambdaTest ECommerce Playground");
   ltOptions.put ("name", "Registration and Login Tests");
   ltOptions.put ("w3c", true);
   ltOptions.put ("plugin", "java-testNG");
   browserOptions.setCapability ("LT:Options", ltOptions);
   return browserOptions;
}

Using the getChromeOptions() method, the capabilities for the Chrome browser and the underlying platform, build, and test names will be set. It will also enable the Java-testNG plugin in the LambdaTest cloud environment. This method will finally return the ChromeOptions to be used while instantiating the RemoteWebDriver session.

Test Execution:

Run the following command to execute the tests on LambdaTest.

mvn clean install -Dsuite-xml=test-suites/testng-pageobjectmodel.xml

Below is the screenshot of the test details of the user registration test executed. LambdaTest provides detailed test information such as the browser name, version, platform, execution logs, along with video recordings and screenshots.LambdaTest Test Execution

What Is Page Factory and How Does It Enhance POM?

While the Page Object Model provides a robust foundation for maintaining clean and reusable test scripts, there’s an advanced implementation called Page Factory that streamlines element initialization and interaction.

In traditional POM, locators are defined explicitly in the page classes and initialized inside constructors or methods. Page Factory simplifies this by using annotations like @FindBy, which automatically locate and initialize elements when the page object is created.

public class LoginPage {
    WebDriver driver;

    @FindBy(id = "input-email")
    private WebElement emailField;

    @FindBy(id = "input-password")
    private WebElement passwordField;

    @FindBy(css = "input[type='submit']")
    private WebElement loginButton;

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

    public void performLogin(String email, String password) {
        emailField.clear();
        emailField.sendKeys(email);
        passwordField.clear();
        passwordField.sendKeys(password);
        loginButton.click();
    }
}

This approach not only improves readability but also supports lazy initialization, meaning elements are only looked up when they are first used. In complex frameworks with multiple shared pages and frequent UI updates, Page Factory reduces boilerplate code and prevents errors caused by manual element initialization.

To get started with Page Factory for web automation, head over to this blog on Page Factory in Selenium.

Conclusion

The Page Object Model is a foundational design pattern that drives effective test automation. It helps in building maintainable, scalable, and robust test automation frameworks with Selenium.

By separating the web elements, actions, and locators into page classes, an abstraction layer is created that keeps test scripts clean and focused on test logic. This reduces code duplication, improves readability, and makes it easier to update tests when the UI changes.

Using platforms like LambdaTest in your testing strategy takes the benefits of POM even further, allowing smooth cross-browser and cross-device testing on real environments. This not only makes test automation more reliable but also helps accelerate release cycles for modern web applications.

Learning Resources for Page Object Model

Explore how the Page Object Model can be implemented across different frameworks and languages with these detailed resources:

Citations

Frequently Asked Questions (FAQs)

What is Page Object Model in Selenium?
Page Object Model in Selenium is a design pattern that creates an object repository for web elements. Each page of the application is represented as a class, separating test scripts from UI elements to enhance maintainability, readability, and reduce code duplication during automation testing.
What is Page Object Model in Selenium Java?
In Selenium Java, the Page Object Model uses Java classes to represent web pages, encapsulating locators and actions in one place. This approach keeps test logic separate from UI code, simplifying maintenance when page elements change and improving reusability across multiple automated test cases.
How to create Page Object Model in Selenium?
To create a Page Object Model in Selenium, define a Java class for each web page, identify web elements using locators, and implement methods for user actions. Then, call these methods within your test scripts, ensuring clean separation between page structure and test logic for easier maintenance.
What is Page Object Model in Playwright?
In Playwright, the Page Object Model organizes automation code by representing each page as a class that defines locators and functions. This structure simplifies test management, keeps tests cleaner, and allows easy updates when the UI changes, especially beneficial for complex web applications.
What is Page Object Model and Page Factory in Selenium?
Page Object Model organizes UI elements and methods in separate page classes, while Page Factory is an extension that initializes web elements using annotations like @FindBy. Together, they reduce code duplication, improve readability, and streamline element handling within Selenium-based automation frameworks.
How to explain Page Object Model framework in an interview?
In an interview, explain that Page Object Model is a design pattern separating test logic from page structure. Each page has a dedicated class containing elements and methods. This structure improves maintainability, reusability, and scalability of automation frameworks, especially when UI components frequently change.
What are the types of Page Object Model?
The main types of Page Object Models include Regular Page Object Model, which uses standard classes and methods, and Page Factory Model, which uses annotations for element initialization. Both serve to separate test logic from UI elements but differ in element management approaches.
What is the difference between the DOM and the Page Object Model?
The Document Object Model (DOM) represents a web page’s structure as a tree of elements that browsers use to render content. The Page Object Model is a design pattern in automation testing that abstracts those elements into reusable objects, improving test maintainability and reducing code duplication.

Did you find this page helpful?

Helpful

NotHelpful

More Related Hubs

ShadowLT Logo

Start your journey with LambdaTest

Get 100 minutes of automation test minutes FREE!!