Contents

    Guides

    Page Object Model in Selenium: Meaning and Importance

    Published on

    September 11, 2025
    Page Object Model in Selenium: Meaning and Importance

    The Page Object Model (POM) in Selenium is a structured design pattern that organizes web page elements and actions into separate classes. It improves the clarity and maintainability of test scripts. POM encapsulates page elements and interactions within dedicated objects. This minimizes code duplication and simplifies updates when the user interface changes.

    This approach helps teams manage automation scripts more efficiently. It supports reusability across different tests and reduces effort when pages change. Tests become easier to read and maintain, which speeds up development cycles. POM also improves consistency across the automation suite, making large-scale testing more reliable and structured. 

    This article explains how the Page Object Model works in Selenium, its implementation, and best practices for building scalable test automation frameworks.

    What is the Page Object Model in Selenium

    The Page Object Model (POM) in Selenium is a design pattern that represents each web page of an application as a separate class. Each class contains the web elements of that page and the actions or methods that can be performed on them. This abstraction separates the test logic from the page structure, making test scripts cleaner and easier to maintain.

    For example, a login page can have a LoginPage class with fields for username, password, and a login button, along with a method to perform the login action. Tests then interact with this class instead of directly accessing page elements, reducing duplication and improving readability.

    Importance of POM for Scalable Test Automation

    The Page Object Model enhances the structure and maintainability of automation scripts. It allows teams to manage UI changes efficiently while keeping tests organized.

    • Reduces Code Duplication: Storing locators and actions in page classes prevents repeating logic across multiple test scripts, ensuring that changes to an element affect all tests consistently.
    • Improves Readability: Test scripts reference clear, meaningful methods from page objects instead of raw locators, making it easier for new team members to understand the flow of tests.
    • Supports Reusability: Common actions, such as logging in or navigating menus, can be reused across different test cases and projects, reducing development effort and errors.
    • Simplifies Maintenance: When UI elements change, only the corresponding page class needs updates, eliminating the need to modify multiple test scripts individually.
    • Enables Scalability: Modular page objects allow large test suites to grow without becoming unmanageable, providing a structured framework for complex applications with multiple pages and workflows.

    Implementing POM: Core Principles and Example Setup

    Implementing the Page Object Model involves creating separate classes for each page of the application. Each class contains the locators for web elements and methods that define actions performed on the page. Tests interact with these classes instead of directly accessing the UI, which keeps test scripts clean and focused on validation rather than implementation details.

    Core Principles of POM

    1. Encapsulation of Page Elements: All elements of a page are stored in one class to centralize maintenance.
    2. Separation of Test Logic and UI Structure: Tests call methods from page classes rather than manipulating elements directly.
    3. Reusability of Methods: Common actions like filling forms, clicking buttons, or navigation are defined once and reused across multiple tests.
    4. Maintainability: Changes in the UI require updates only in the corresponding page class, not across all test scripts.

    Consider a web application with a login page. A tester wants to automate logging in with valid credentials. Instead of writing locators and actions directly in the test script, a LoginPage class can encapsulate all elements and actions related to login. 

    This class stores the locators for the username, password, and login button, and provides methods to interact with them. A combined login method allows performing the full login in a single call, keeping tests clean and maintainable.

    import org.openqa.selenium.WebDriver;

    import org.openqa.selenium.WebElement;

    import org.openqa.selenium.By;

    public class LoginPage {

        WebDriver driver;

        public LoginPage(WebDriver driver) {

            this.driver = driver;

        }

        // Locators for username, password, and login button

        By usernameField = By.id("username");

        By passwordField = By.id("password");

        By loginButton = By.id("loginBtn");

        // Methods to interact with page elements

        public void enterUsername(String username) {

            driver.findElement(usernameField).sendKeys(username); // Enter username

        }

        public void enterPassword(String password) {

            driver.findElement(passwordField).sendKeys(password); // Enter password

        }

        public void clickLogin() {

            driver.findElement(loginButton).click(); // Click login button

        }

        // Combined action to perform login

        public void login(String username, String password) {

            enterUsername(username);

            enterPassword(password);

            clickLogin();

        }

    }

    Once the page class is defined, the test script can use it to perform login. This separates the test logic from the page structure, making tests easier to read, maintain, and reuse.

    import org.openqa.selenium.WebDriver;

    import org.openqa.selenium.chrome.ChromeDriver;

    import org.testng.annotations.*;

    public class LoginTest {

        WebDriver driver;

        @BeforeMethod

        public void setup() {

            driver = new ChromeDriver();          // Open Chrome browser

            driver.get("https://example.com/login"); // Navigate to login page

        }

        @Test

        public void validLoginTest() {

            LoginPage loginPage = new LoginPage(driver); // Create page object

            loginPage.login("testuser", "password123");  // Perform login

            // Add assertions here to verify successful login

        }

        @AfterMethod

        public void teardown() {

            driver.quit(); // Close browser after test

        }

    }

    Where Page Factory Fits into the Page Object Model

    Page Factory is a Selenium feature that simplifies the implementation of the Page Object Model by handling the initialization of web elements automatically. 

    Instead of manually locating elements with driver.findElement, Page Factory uses annotations like @FindBy to define elements, which are then initialized when the page class is instantiated. This reduces boilerplate code and makes page classes cleaner and easier to manage.

    For example, the LoginPage can be rewritten using Page Factory so that all elements are automatically initialized, but the test script still interacts with the page through the same methods. This maintains the separation of test logic and page structure while improving readability and maintainability.

    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;

        public LoginPage(WebDriver driver) {

            this.driver = driver;

            PageFactory.initElements(driver, this); // Initialize elements using Page Factory

        }

        @FindBy(id = "username")

        WebElement usernameField; // Username input field

        @FindBy(id = "password")

        WebElement passwordField; // Password input field

        @FindBy(id = "loginBtn")

        WebElement loginButton; // Login button

        // Methods to interact with page elements

        public void enterUsername(String username) {

            usernameField.sendKeys(username);

        }

        public void enterPassword(String password) {

            passwordField.sendKeys(password);

        }

        public void clickLogin() {

            loginButton.click();

        }

        public void login(String username, String password) {

            enterUsername(username);

            enterPassword(password);

            clickLogin();

        }

    }

    In this version, Page Factory automatically handles element initialization, reducing repetitive findElement calls. The test script using this class remains the same, keeping the workflow modular and consistent.

    Implementing Page Factory with an Example Project Structure

    Consider a web application with a login page. A tester wants to automate logging in with valid credentials. Using Page Factory simplifies element initialization while keeping the Page Object Model structure intact. All elements are defined with annotations and automatically initialized when the page class is instantiated, so the test script can focus purely on workflow and validation.

    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;

        public LoginPage(WebDriver driver) {

            this.driver = driver;

            PageFactory.initElements(driver, this); // Initialize elements using Page Factory

        }

        @FindBy(id = "username")

        WebElement usernameField; // Username input field

        @FindBy(id = "password")

        WebElement passwordField; // Password input field

        @FindBy(id = "loginBtn")

        WebElement loginButton; // Login button

        // Methods to interact with page elements

        public void enterUsername(String username) {

            usernameField.sendKeys(username);

        }

        public void enterPassword(String password) {

            passwordField.sendKeys(password);

        }

        public void clickLogin() {

            loginButton.click();

        }

        public void login(String username, String password) {

            enterUsername(username);

            enterPassword(password);

            clickLogin();

        }

    }

    The test script uses the page object in the same way as standard POM, maintaining separation of test logic and page structure while benefiting from cleaner code.

    import org.openqa.selenium.WebDriver;

    import org.openqa.selenium.chrome.ChromeDriver;

    import org.testng.annotations.*;

    public class LoginTest {

        WebDriver driver;

        @BeforeMethod

        public void setup() {

            driver = new ChromeDriver();          // Open Chrome browser

            driver.get("https://example.com/login"); // Navigate to login page

        }

        @Test

        public void validLoginTest() {

            LoginPage loginPage = new LoginPage(driver); // Create page object with Page Factory

            loginPage.login("testuser", "password123");  // Perform login

            // Add assertions to verify successful login

        }

        @AfterMethod

        public void teardown() {

            driver.quit(); // Close browser after test

        }

    }

    Using Page Factory, all elements are automatically initialized, reducing boilerplate code and making page classes cleaner. The test script remains readable, maintainable, and fully aligned with Page Object Model principles, making it easier to scale automation across larger applications.

    Comparing POM and Page Factory: Key Differences 

    The Page Object Model (POM) and Page Factory both organize test automation by separating page structure from test logic, but they differ in how elements are defined and initialized. 

    POM requires manual initialization of elements using driver.findElement, giving full control over locating elements but requiring more boilerplate code. Page Factory uses annotations like @FindBy to automatically initialize elements when the page class is instantiated, reducing repetitive code and improving readability.

    Feature Page Object Model (Manual) Page Factory (Automatic)
    Element Initialization Manual using driver.findElement inside methods Automatic using @FindBy and PageFactory.initElements()
    Code Readability More verbose due to manual element handling Cleaner and more readable because element initialization is automatic
    Performance Elements are located as methods are called Supports lazy loading; elements are looked up only when used
    Use Cases Suitable for small to medium projects where manual control is preferred Ideal for large projects with many pages or frequent UI changes
    Maintenance Changes in locators require manual updates in methods Changes in locators require updates only in annotated fields

    Example Scenario:

    In a login page, POM requires calling driver.findElement for each field and button. Using Page Factory, these elements are annotated and automatically initialized, so the test can simply call loginPage.login(username, password) without managing element initialization manually.

    Both approaches maintain modularity and separation of test logic from page structure. Choosing between them depends on project size, team preference, and the need for cleaner code versus full control over element handling.

    Best Practices for Building and Maintaining Page Objects

    Building page objects correctly is crucial to ensure that automation scripts remain maintainable, readable, and scalable. Following best practices helps teams avoid common pitfalls such as code duplication, brittle tests, and difficulty in updating locators when the UI changes.

    • Encapsulate Page Elements: Keep all locators and actions for a page within a single class. For example, a LoginPage should include only username, password fields, login button, and methods to interact with them. This prevents duplication and centralizes maintenance.
    • Use Meaningful Method Names: Methods should clearly describe the action they perform, such as enterUsername(), clickLogin(), or login(). This improves readability and makes test scripts self-explanatory.
    • Avoid Test Logic in Page Classes: Page classes should handle interactions only. Assertions and validations should remain in test scripts to keep responsibilities separate.
    • Leverage Page Factory for Element Initialization: Using @FindBy annotations reduces repetitive findElement calls and supports lazy loading, improving performance and maintainability in larger applications.
    • Keep Page Objects Small and Focused: Each page class should represent a single page or a logically cohesive component. Avoid bloating classes with unrelated elements or actions.
    • Handle Dynamic Elements Carefully: For elements that change frequently or load asynchronously, use explicit waits or dynamic locators within page methods rather than hardcoding assumptions in tests.
    • Regularly Review and Refactor: As the application evolves, update page objects to reflect UI changes and remove deprecated methods to prevent confusion and test failures.

    Conclusion

    The Page Object Model and Page Factory provide a structured approach to building maintainable and scalable Selenium test automation frameworks. By encapsulating page elements and actions within dedicated classes, teams can reduce code duplication, simplify maintenance, and improve readability across large test suites. 

    For teams looking to scale Selenium testing across multiple browsers and devices, BrowserStack Automate offers a cloud-based platform to run these tests efficiently. It allows executing scripts on real browsers and devices, provides parallel execution for faster results, and integrates seamlessly with existing frameworks. 

    Run Selenium Tests on Cloud

    Data-rich bug reports loved by everyone

    Get visual proof, steps to reproduce and technical logs with one click

    Make bug reporting 50% faster and 100% less painful

    Rating LogosStars
    4.6
    |
    Category leader

    Liked the article? Spread the word

    Put your knowledge to practice

    Try Bird on your next bug - you’ll love it

    “Game changer”

    Julie, Head of QA

    star-ratingstar-ratingstar-ratingstar-ratingstar-rating

    Overall rating: 4.7/5

    Try Bird later, from your desktop