📣 Requestly API Client – Free Forever & Open Source. A powerful alternative to Postman. Try now ->

What is Page Object Model in Selenium: Principles and Examples

Rohit Rajpal
Learn what the Page Object Model in Selenium is, its principles, examples, and how Page Factory extends POM for scalable test automation.
What is Page Object Model in Selenium Principles and Examples

The Page Object Model in Selenium is a design pattern that separates test scripts from the underlying web page structure. Each page or component is represented by a class containing locators and methods, making tests easier to read, maintain, and scale.

By encapsulating page details, POM reduces duplication and minimizes maintenance effort when the UI changes. It allows testers to write cleaner, more stable automation and enables collaboration across teams without tightly coupling tests to specific page elements.

This article explains how the Page Object Model works, its core principles, and practical implementation strategies for effective Selenium automation.

What is the Page Object Model in Selenium

The Page Object Model, or POM, is a design pattern that separates test logic from the underlying web page structure in Selenium automation. Each page or component is represented as a class containing locators and methods.

This makes test scripts easier to read, maintain, and scale, which is especially important for large projects with multiple pages and complex workflows.

Storing all page-related details within these classes reduces repetition in the test code and makes updates simpler when the UI changes. Test scripts remain consistent and easier to manage, while teams can work on automation without tightly coupling test logic to specific page elements.

Why Use the Page Object Model?

Test automation projects can become difficult to maintain if page details and test logic are mixed together. The Page Object Model organizes automation code to improve readability, maintainability, and stability.

Below are the main reasons why POM is widely adopted in professional Selenium projects:

  • Separation of Concerns: Test scripts focus only on test logic while page classes handle locators and actions. This separation makes the automation code more organized and easier to follow.
  • Reduced Code Duplication: Common actions and locators are stored in page classes so multiple tests can reuse them instead of redefining the same code.
  • Easier Maintenance: When UI elements change, updates are made only in the relevant page classes. Test scripts remain unchanged, which minimizes the risk of introducing errors.
  • Improved Test Stability: With a clear structure and encapsulated locators, tests are less likely to break due to minor UI changes.
  • Enhanced Collaboration: Teams can work in parallel. Developers maintain page classes while testers focus on test scripts without interfering with each other’s work.
  • Scalability for Large Projects: As projects grow, POM supports adding new pages and features without making existing tests messy or unmanageable.
  • Better Readability: Methods in page classes often have descriptive names that explain actions clearly. Tests read almost like plain English, improving understanding for new team members.

Core Principles Behind POM

The Page Object Model is based on a few key principles that ensure automation is maintainable, reusable, and scalable. Understanding these principles helps testers design robust frameworks that can adapt to changes in the application without breaking tests.

Below are the core principles that guide POM implementation in Selenium projects:

  • Single Responsibility: Each page class should represent only one page or component. It contains locators and methods relevant to that page, keeping classes focused and easier to maintain.
  • Encapsulation: Page details, such as locators and internal methods, are hidden from test scripts. Tests interact with pages only through public methods, reducing dependency on implementation details.
  • Reusability: Actions that are common across multiple tests are defined once in the page class. This avoids code duplication and ensures consistent behavior across tests.
  • Maintainability: Changes in the UI require updates in a single place—the relevant page class. This reduces maintenance effort and prevents multiple test failures.
  • Readability: Methods and variables in page classes are named descriptively, making test scripts easier to read and understand even for team members who are new to the project.
  • Modularity: Tests and page objects are modular, allowing teams to work independently on test scripts or page classes. This supports parallel development and reduces conflicts.
  • Scalability: Adding new pages, actions, or features does not affect existing tests if the principles of POM are followed. The framework grows smoothly with the application.

How to Set Up Page Object Model in Selenium Tests

Setting up the Page Object Model requires a structured approach that separates page details from test scripts. A consistent setup ensures tests remain maintainable, readable, and scalable.

Below are the steps to set up POM in Selenium tests:

Step 1: Organize Project Structure

Create separate folders or packages for page classes, test scripts, and utility functions. For example, use pages for page classes, tests for test scripts, and utils for reusable helper functions. This keeps the project organized and easy to navigate.

Step 2: Create Page Classes

For each web page, create a corresponding class containing locators and methods. For example, a LoginPage class should include locators for username, password, and login button, along with methods to interact with them.

Step 3: Define Locators Clearly

Use descriptive variable names for web elements and follow a consistent locator strategy such as ID, name, or XPath. Clear locators make the code easier to maintain and understand.

Step 4: Implement Page Methods

Write methods in page classes for actions such as entering text, clicking buttons, or validating elements. Each method should perform a single, well-defined action to keep the code modular.

Step 5: Initialize Page Classes

Use constructors in page classes to initialize web elements by passing the WebDriver instance. This avoids hard-coding the driver and keeps page classes flexible.

Step 6: Keep Test Scripts Clean

Test scripts should only call page methods and perform assertions. Avoid including locators or direct Selenium commands in the test scripts.

Step 7: Add Utility Methods

For common functions like waiting for elements, handling alerts, or scrolling, create reusable utility methods instead of duplicating code across page classes.

Step 8: Follow Naming Conventions

Use consistent naming conventions for classes, methods, and variables. Descriptive names improve readability and help team members quickly understand the purpose of each component.

Sample POM Project Example

A sample project makes it easier to understand how the Page Object Model works in practice. Below is a project layout and code snippets showing how to organize page classes and test scripts using Selenium.

1. Project Structure

A typical folder layout for a POM-based Selenium project can look like this:

				
					/selenium-pom-project
   /src
      /pages
         LoginPage.java
         HomePage.java
      /tests
         LoginTest.java
      /utils
         WebDriverFactory.java
				
			
  • pages: Contains page classes for different application pages.
  • tests: Contains test scripts that call methods from page classes.
  • utils: Contains helper classes like driver setup, waits, or configurations.

2. Page Class Example

Example

				
					LoginPage.java:
public class LoginPage {
    WebDriver driver;

    // Locators
    By usernameField = By.id("username");
    By passwordField = By.id("password");
    By loginButton = By.id("login");

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

    // Actions
    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();
    }
}
				
			

3. Test Script Example

Example

				
					LoginTest.java:
public class LoginTest {
    WebDriver driver;

    @BeforeMethod
    public void setUp() {
        driver = new ChromeDriver();
        driver.get("https://example.com/login");
    }

    @Test
    public void testValidLogin() {
        LoginPage loginPage = new LoginPage(driver);
        loginPage.enterUsername("testuser");
        loginPage.enterPassword("password123");
        loginPage.clickLogin();

        // Assertion example
        Assert.assertEquals(driver.getTitle(), "Home Page");
    }

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

Reusability

Once created, the LoginPage class can be reused in multiple test cases without redefining locators or actions. Any UI change to the login page requires updates only in LoginPage.java, while all test scripts continue to work.

Page Factory in Selenium: An Extension of POM

Page Factory is an enhancement of the Page Object Model that makes element initialization simpler and more efficient. Instead of manually writing a driver.findElement() calls inside page classes, Page Factory uses annotations to define locators and initializes them automatically. This reduces boilerplate code and improves readability.

The concept remains the same as POM: each page has its own class, and all actions are defined as methods. The main difference is how elements are declared and initialized. Page Factory also provides lazy initialization, which means elements are only located when they are used in a test.

Key points that distinguish Page Factory from a regular POM implementation include:

  • Use of Annotations: Web elements are defined using @FindBy annotations instead of traditional By locators.
  • Automatic Initialization: Elements are initialized with the PageFactory.initElements() method, removing the need for repeated findElement calls.
  • Lazy Element Location: Elements are located only when they are accessed, which improves performance and reduces unnecessary lookups.
  • Improved Readability: The code looks cleaner because locators are declared at the top of the class, and actions focus only on page behavior.
  • Integration with Standard POM: Page Factory is not a replacement but an extension. It works with the same principles as POM while simplifying locator handling.

Implementing Page Factory in Selenium Tests

Implementing Page Factory in Selenium follows the same structure as a regular Page Object Model setup. The difference lies in how web elements are declared and initialized. Instead of defining locators using the By class, Page Factory uses annotations like @FindBy. These elements are then initialized with PageFactory.initElements().

Below is an example showing how to implement Page Factory in a login page scenario:

Page Class with Page Factory

LoginPage.java:

				
					import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class LoginPage {
    WebDriver driver;

    // Locators with annotations
    @FindBy(id = "username")
    WebElement usernameField;

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

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

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

    // Actions
    public void enterUsername(String username) {
        usernameField.sendKeys(username);
    }

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

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

Test Script Using Page Factory

LoginTest.java:

				
					import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.*;

public class LoginTest {
    WebDriver driver;

    @BeforeMethod
    public void setUp() {
        driver = new ChromeDriver();
        driver.get("https://example.com/login");
    }

    @Test
    public void testValidLogin() {
        LoginPage loginPage = new LoginPage(driver);
        loginPage.enterUsername("testuser");
        loginPage.enterPassword("password123");
        loginPage.clickLogin();

        // Assertion example
        Assert.assertEquals(driver.getTitle(), "Home Page");
    }

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

Key Observations

  • Locators are defined once using annotations and look cleaner at the top of the class.
  • PageFactory automatically initializes elements when the constructor runs.
  • Test scripts remain focused on logic and assertions, without worrying about element lookups.

Example Project Layout with Page Factory

A Page Factory–based project has a structure similar to a regular POM setup. The difference lies in how page classes are written and initialized. Keeping a clean project layout ensures that the framework remains maintainable as the application grows.

A typical layout for a Selenium project using Page Factory looks like this:

				
					/selenium-pagefactory-project
   /src
      /pages
         LoginPage.java
         HomePage.java
         ProfilePage.java
      /tests
         LoginTest.java
         ProfileTest.java
      /utils
         WebDriverFactory.java
         ConfigReader.java
				
			
  • pages: Contains all page classes with @FindBy annotations and methods for actions.
  • tests: Contains test classes that call page methods and perform assertions.
  • utils: Contains reusable utilities such as driver setup, configuration handling, and wait conditions.

Page Object Model vs Page Factory in Selenium

Both Page Object Model (POM) and Page Factory aim to improve test automation design in Selenium. They share the same foundation of separating page structure from test logic, but their approaches differ in how elements are located and managed.

Below is a detailed comparison of POM and Page Factory:

Aspect

Page Object Model

Page Factory

Element Definition

Uses By locators inside page classes

Uses @FindBy annotations to declare elements

Element Initialization

Requires an explicit driver.findElement() calls

Uses PageFactory.initElements() for automatic initialization

Code Readability

Slightly verbose due to repeated locator calls

Cleaner, as locators are declared once at the top of the class

Performance

Elements are always located when methods are executed

Supports lazy initialization; elements are located only when needed

Ease of Maintenance

Effective, but can become verbose in large projects

More concise and easier to manage in complex test suites

Learning Curve

Simple for beginners, as it is closer to raw Selenium usage

Requires understanding annotations and initialization concepts

When to Use Each Approach

  • POM is suitable for projects where explicit control over element initialization is needed or where the team prefers a straightforward implementation.
  • Page Factory is more effective in medium to large projects where readability, reduced boilerplate, and lazy initialization bring clear benefits.

However, both can coexist within the same project. For example, teams may start with a standard POM and gradually adopt Page Factory as the framework matures.

Design Patterns Commonly Applied in Selenium Automation

Page Object Model forms the base of most Selenium frameworks, but additional design patterns are often applied to make the framework more robust, scalable, and easier to maintain. These patterns are widely recognized in software engineering and help manage complexity when automation suites grow in size.

Below are some of the most common design patterns used with Selenium automation:

  • Singleton Pattern: Ensures only one instance of the WebDriver is created during the test run. This prevents conflicts caused by multiple driver instances and provides a centralized way to manage browser sessions.
  • Factory Pattern: Provides a standard approach to creating WebDriver instances across different browsers. Instead of hardcoding browser setup in tests, a factory class generates the required driver, making cross-browser testing easier.
  • Strategy Pattern: Allows different element locator strategies (like By.id, By.cssSelector, or By.xpath) to be swapped without changing the main code. This makes locator management flexible when working with complex UIs.
  • Facade Pattern: Wraps multiple page actions into higher-level methods that represent complete workflows. For example, instead of calling three methods separately for entering username, password, and clicking login, a single loginAs(user, pass) method can be exposed.
  • Observer Pattern: Helps in scenarios like event-driven testing, where actions such as logging or screenshot capture should occur automatically whenever a test step runs.

Conclusion

The Page Object Model in Selenium provides a structured way to build stable automation frameworks. It separates page locators and actions from test logic, which reduces duplication and keeps tests maintainable. Page Factory extends these benefits by simplifying element initialization through annotations, making it easier to scale automation in larger projects.

Running these tests on local machines has limits, especially for cross-browser and cross-device coverage. BrowserStack enables teams to execute Selenium tests on 3,000+ real browsers and devices, ensuring that frameworks built with POM and Page Factory deliver reliable results across environments.

Written by
Rohit Rajpal
Rohit Rajpal is a B2B Content Strategist at BrowserStack, helping SaaS brands build AI-first strategies that drive authority and revenue. He writes about content, strategy, and the future of search in the zero-click era.

Related posts