When a developer renames a button, a fragile UI test suite can break in dozens of places. That is the maintenance problem the Page Object Model was designed to solve.
Without a consistent pattern, UI tests often reach directly into the page, scatter CSS selectors and XPath expressions across test files, and inherit every front-end refactor the development team makes. The Page Object Model, often shortened to POM, wraps each page, screen, or component in a class that exposes user actions and hides locator details. When an element changes, you update the page object instead of hunting through every test that uses it.
This guide explains what POM is, how it works in Java and Selenium, the rules that keep it maintainable, and where the pattern can start to strain. It also compares POM with another way to solve the same maintainability problem: a centralized visual object repository, which is how Ranorex Studio helps teams manage UI elements across desktop, web, and mobile testing.
| Tired of fixing the same locators in fifty test files? Walk us through your current setup, and we will show you how teams cut maintenance time with a centralized object repository. |
Key takeaways
- POM is a design pattern, not a tool. It organizes UI automation code, so tests interact with page-level actions rather than raw locators.
- A good page object hides selectors, exposes meaningful user actions, and keeps test code easier to read and maintain.
- Page Factory is not the same thing as POM. It is a Selenium helper for initializing page objects, but teams can implement POM without using Page Factory.
- Page objects should generally avoid test-specific assertions. A page object may check that the page loaded correctly, but scenario-level assertions belong in the test.
- POM works especially well for code-first teams building Selenium-based web automation. Teams with mixed skill sets or broader desktop, web, and mobile coverage may benefit from a visual object repository like the Ranorex Repository.

What is a page object model?
The Page Object Model is a design pattern for organizing UI test automation. Each page, view, screen, or meaningful component in the application under test is represented by a class. That class usually contains two things:
- Locators for elements on the page, such as fields, buttons, links, tables, and messages
- Methods that represent actions a user can take, such as logging in, searching, filtering, submitting a form, or adding an item to a cart
Tests do not interact with page elements directly. Instead, they call methods on page objects. This keeps test code focused on the behavior being tested and keeps locator details in one place.
For example, if a developer changes #login-button to #submit-login, you update the locator inside LoginPage.java. Every test that logs in through that page object can continue using the same login() method.
POM is most commonly discussed in Selenium-based web automation, but the broader pattern is not limited to one tool. The core idea is simple: separate test intent from UI element identification so the test suite is easier to read, reuse, and maintain.
The pattern in practice: A LoginPage example
Here is a minimal LoginPage example in Java with Selenium WebDriver. This version does not use Page Factory or annotations. It uses plain page objects with By locators.
public class LoginPage {
private final WebDriver driver;
private final By usernameField = By.id("username");
private final By passwordField = By.id("password");
private final By loginButton = By.cssSelector("button[type='submit']");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public HomePage loginAsValidUser(String username, String password) {
driver.findElement(usernameField).sendKeys(username);
driver.findElement(passwordField).sendKeys(password);
driver.findElement(loginButton).click();
return new HomePage(driver);
}
public LoginPage loginAsInvalidUser(String username, String password) {
driver.findElement(usernameField).sendKeys(username);
driver.findElement(passwordField).sendKeys(password);
driver.findElement(loginButton).click();
return this;
}
public boolean errorMessageIsVisible() {
return driver.findElement(By.id("login-error")).isDisplayed();
}
}
The test that uses it reads closer to a user workflow:
@Test
public void userCanLogInAndSeeDashboard() {
LoginPage loginPage = new LoginPage(driver);
HomePage homePage = loginPage.loginAsValidUser("alice", "correcthorse");
assertTrue(homePage.welcomeBannerIsVisible());
}
The important point is not the exact Java syntax. It is the separation of responsibilities.
The page object knows where elements are and how to interact with them. The test knows what behavior it is verifying. If the login button changes, the locator changes in one place. If the expected result changes, the test assertion changes.
Rules that keep POM working in practice
POM is simple to understand, but it still requires discipline. Without shared conventions, teams can end up with a different kind of maintenance problem: too many page classes, duplicated locators, unclear return types, and test logic hidden inside page objects. The following are the rules that matter most in practice.
Model logical screens, not just URLs
A page object should represent a logical page, screen, or view in the product. That does not always map cleanly to a URL.
A modal that appears on multiple pages should usually be modeled as its own component. A multi-step wizard may deserve separate page objects for each step, even if the URL never changes. A reusable navigation bar, side panel, or confirmation dialog should not be duplicated across every page object that uses it.
The goal is to model the application so that tests are easier to understand and maintain.
Keep test-specific assertions out of page objects
Page objects should represent what a user can do on a page. Tests should represent what the team is trying to verify.
That means test-specific assertions usually belong in the test, not the page object. A page object can expose methods such as welcomeBannerIsVisible() or getErrorMessageText(), but the test should decide what to assert.
One exception is page readiness. A page object can verify that the expected page or critical elements are loaded correctly when the object is created. That kind of check helps prevent tests from continuing on the wrong page.
Return the page or component the user lands on
Page object methods should make navigation clear.
If a successful login takes the user to the home page, loginAsValidUser() should return a HomePage. If an invalid login keeps the user on the login page, use a separate method, such as loginAsInvalidUser(), that returns LoginPage, or use another clear convention, such as a result object.
Avoid returning a generic Object and forcing the test to cast it. That may work technically, but it makes the framework harder to understand and easier to misuse.
Treat shared UI elements as components
Not everything is a full page. Navigation bars, footers, menus, tables, filters, modals, and confirmation dialogs often appear across multiple pages.
Instead of copying those locators into several page objects, wrap them in component objects and compose them into the pages that use them. This keeps shared UI behavior in one place and makes updates easier when reusable components change.
Standardize waits and synchronization
POM centralizes locators, but it does not automatically solve flaky timing issues. If tests fail because elements load asynchronously, animations delay interactions, or network calls finish at unpredictable times, page objects need reliable wait strategies.
Most teams create shared utilities for explicit waits, retries, and expected conditions. The key is to maintain consistent synchronization so that every page object does not reinvent its own wait logic.
A note on Page Factory
Page Factory is a Selenium helper that initializes page elements using annotations such as @FindBy. Many tutorials introduce Page Factory alongside POM, which is why the two are sometimes confused.
They are not the same thing.
POM is the design pattern. Page Factory is one possible way to implement part of that pattern.
In Java, Selenium still includes the PageFactory class in the support library. It can make simple page objects easier to set up, but teams should be careful with dynamic pages, cached elements, and AJAX-heavy interfaces where stale elements and timing issues are common.
In .NET, PageFactory is no longer part of the core Selenium bindings in the same way. The implementation lives on in the DotNetSeleniumExtras package, which replaces the original Selenium implementation.
For new projects, many teams choose plain page objects with By locators and explicit findElement calls because the code is easier to read and debug, and less dependent on annotation-driven behavior. Page Factory can still be useful in some contexts, but it should not be treated as required for POM.
Where POM starts to strain
POM solves one major problem very well: locator scatter.
Instead of placing selectors throughout every test, you centralize them in page objects. That makes UI changes easier to manage and keeps test code more readable.
But POM does not solve every UI automation problem.
Locator volatility still requires maintenance
If the development team changes markup every sprint, your locators may still need frequent updates. POM reduces the number of places you need to edit, but it does not eliminate the need to maintain locators.
Flaky timing still needs synchronization
If tests fail because elements are not ready, animations are still running, or API calls finish late, POM alone will not fix that. You still need reliable wait patterns, stable test data, and a clean environment setup.
Large applications can produce many page objects
Enterprise applications can easily grow into dozens or hundreds of page objects and components. Without naming conventions, folder structure, and ownership rules, teams may spend too much time finding the right class to update.
Multi-platform coverage can add complexity
POM is most commonly used with Selenium and web automation. The pattern can be adapted to other UI automation contexts, but teams covering desktop, web, mobile, embedded WebViews, or hybrid apps may still need to maintain different frameworks, locator strategies, and toolchains for each platform.
That is where a centralized object repository can be a better fit for some teams.
| Covering desktop and web together? Most teams running both end up with two parallel frameworks. We can walk you through how Ranorex Studio handles desktop, web, and mobile in one project. Book a working session. |
Page Object Model vs. a visual object repository
POM and a visual object repository are two different ways to address the same maintainability goal: centralize UI element identification so that a change updates a single place instead of many.
The difference is where that centralization lives.
| Approach | Where locators live | Best fit |
| Page Object Model | In source code, usually inside page or component classes | Code-first teams standardized on Selenium or another framework, especially for web automation |
| Visual object repository | In a structured repository file managed through an IDE | Mixed-skill teams, teams that want less code-based locator maintenance, or teams testing across desktop, web, and mobile |
| Ranorex Repository | In an .rxrep repository file with RanoreXPath definitions and a tree-structured UI model | Teams using Ranorex Studio to manage object identification across desktop, web, and mobile tests |
With POM, element identification lives in code. Developers and automation engineers maintain locators in page classes, review changes through source control, and use language-level refactoring tools.
In the Ranorex Repository, UI elements are organized in a tree that reflects the application under test’s structure. App folders represent top-level application windows or pages. Rooted folders represent sections of the UI that contain related elements. Repository items represent the individual UI elements used in tests.
A RanoreXPath identifies each repository item. Because repository items can inherit path context from parent folders, teams can update shared path definitions higher in the tree, reducing repetitive locator maintenance. Ranorex also stores the repository in an .rxrep file and generates a code representation from it.
The goal is similar to POM, but the workflow is different. Instead of editing locators directly in page classes, teams can manage UI element definitions through the Ranorex Studio IDE. That can be useful for teams where testers, automation engineers, and developers all contribute to test maintenance.
Which approach fits your team?
There is no universal right answer. The right approach depends on your team’s skills, application types, automation maturity, and maintenance pain points.
Use POM when your team is code-first and web-focused
POM is a strong fit when your team is standardized on Selenium or another code-based web automation framework. It works especially well when automation engineers are comfortable maintaining test code, reviewing pull requests, and building shared utilities for waits, retries, data setup, and reusable components.
For new Selenium projects, plain page objects are often easier to maintain than Page Factory-based implementations because the code is explicit and easier for new contributors to follow.
Consider a visual object repository when locator maintenance needs to be more accessible
A visual object repository may be a better fit when non-coding testers help maintain automated tests, when the team wants locator definitions managed through an IDE, or when UI element identification needs to be shared across a broader group.
This approach can also help when teams want a structured view of the application’s UI elements instead of locating everything through code.
Consider Ranorex Studio when you need desktop, web, and mobile coverage
Teams that test across multiple application types often face more than one locator problem. They may have Selenium tests for web, separate tools for desktop, and another framework for mobile.
Ranorex Studio supports desktop, web, and mobile test automation in one environment, with the Ranorex Repository acting as a central place to manage object identification. That can reduce the need to maintain separate locator strategies across multiple tools, depending on the team’s existing stack and coverage needs.
Audit the real source of test maintenance before changing frameworks
Before choosing POM, Page Factory, or a visual object repository, identify the source of your test maintenance.
If failures are caused by locator churn, centralizing UI element identification can help. If failures are caused by timing, unstable environments, test data issues, or unclear ownership, changing the locator pattern alone will not fix the suite.
The best automation framework is not just the one with the cleanest design pattern. It is the one your team can maintain consistently.
Build a test suite that survives UI change
The Page Object Model remains one of the most useful patterns in UI test automation because it gives teams a clean way to separate test intent from UI implementation details. When page objects are well designed, tests are easier to read, locators are easier to update, and shared UI behavior is easier to reuse.
But POM is not the only way to solve the locator maintenance problem. A visual object repository can provide the same centralization in a more accessible, tool-supported workflow, especially for teams working across multiple application types or with a mix of coding and non-coding testers.
Whether you use POM in code or manage UI elements through the Ranorex Repository, the principle is the same: define each UI element once, reuse it consistently, and make changes easier to absorb.
If your team is spending too much time fixing broken locators, rebuilding flaky tests, or maintaining separate frameworks for different application types, Ranorex Studio can help you centralize object recognition and manage automated testing across desktop, web, and mobile applications.
Frequently asked questions
What is the Page Object Model in Selenium?
The Page Object Model is a design pattern for organizing Selenium tests. Each page, screen, or major component is represented by a class that contains the locators and methods needed to interact with that part of the application. Tests call methods on page objects rather than interacting with elements directly, making the test code easier to read and helping centralize locator maintenance.
Is Page Factory deprecated?
It depends on the language binding. In .NET, PageFactory is no longer maintained as part of the core Selenium bindings and is now available through the DotNetSeleniumExtras package. In Java, Selenium still includes the PageFactory class in the support library. However, many teams prefer plain page objects for new projects because they are explicit, easier to debug, and less prone to confusion around cached or dynamically loaded elements.
What is the difference between Page Object Model and Page Factory?
Page Object Model is a design pattern. Page Factory is a Selenium helper that can be used to initialize page elements, often through annotations such as @FindBy.
You can use POM with or without Page Factory. A page object that stores By locators and uses explicit findElement calls is still a valid implementation of POM.
Should page objects include assertions?
Page objects should generally avoid test-specific assertions. The test should decide what behavior is being verified. However, a page object can include checks to confirm that the page or critical elements are loaded correctly when the object is created. That helps prevent the test from continuing when it is on the wrong page or when the expected UI is not ready.
How is Ranorex Repository different from Page Object Model?
Both approaches centralize UI element identification, but in different places. POM stores locators in source code, usually inside page or component classes. The Ranorex Repository stores UI elements in a separate .rxrep file, organized in a tree structure, and is edited through Ranorex Studio.
The Ranorex Repository uses RanoreXPath to identify UI elements and supports desktop, web, and mobile test automation in a single environment.
When should I use POMs instead of a visual object repository?
Use POM when your team is code-first, primarily focused on web automation, and comfortable maintaining page and component classes in languages like Java, C#, Python, or JavaScript.
Consider a visual object repository when your team includes non-coding testers, when locator maintenance needs to be more accessible, or when your automation coverage spans desktop, web, and mobile applications. Many larger teams use both approaches in different parts of their test strategy.



