Page Object Model with Cucumber
What Is Page Object Model?
Page Object Model, often called POM, is a Selenium design pattern where each page or major reusable UI component is represented by a Java class. The class contains locators, page-specific actions, and methods that describe what a user can do on that page.
When POM is used with Cucumber, feature files describe behavior, step definitions coordinate the scenario flow, and Page Objects perform the Selenium UI interactions. This gives every layer a clear responsibility.
Why Use POM with Cucumber?
Without POM, Selenium code often lands directly in step definitions. The result is duplicated locators, long step methods, difficult debugging, and tightly coupled automation. A small UI change can force edits across many step definition files.
With POM, the locator and interaction logic stay in one page class. If the login button ID changes, the LoginPage class is updated. The Gherkin scenario and the step definition can stay unchanged when the business behavior remains the same.
Overall Architecture
Feature File
-> Step Definition
-> Page Object
-> WebDriver
-> Browser
This architecture prevents Cucumber from becoming a Selenium script written in English. The scenario remains business-readable, while the implementation remains maintainable Java code.
Layer Responsibilities
The feature file describes business behavior. The step definition maps Gherkin steps to Java methods. The Page Object performs UI operations. WebDriver communicates with the browser. The browser executes the actual user actions against the application.
| Layer | Responsibility |
|---|---|
| Feature File | Describe behavior |
| Step Definition | Coordinate scenario execution |
| Page Object | Perform UI interactions |
| WebDriver | Control browser |
Typical Project Structure
src/test/java
runners
hooks
stepdefinitions
pages
utilities
drivers
src/test/resources
features
The pages package contains Page Objects such as LoginPage, HomePage, CustomerPage, PaymentPage, and SearchPage. Step definitions use those page classes rather than locating elements directly.
Feature File Example
Feature: Login
Scenario: Valid login
Given the user is on the login page
When the user logs in with "admin" and "admin123"
Then the dashboard should be displayed
The feature file does not mention driver.findElement(), XPath, CSS selectors, or waits. It expresses the expected behavior.
Step Definition Example
public class LoginSteps {
private LoginPage loginPage = new LoginPage();
@Given("the user is on the login page")
public void openLoginPage() {
loginPage.open();
}
@When("the user logs in with {string} and {string}")
public void login(String username, String password) {
loginPage.login(username, password);
}
@Then("the dashboard should be displayed")
public void verifyDashboard() {
Assert.assertTrue(loginPage.isDashboardDisplayed());
}
}
Notice that the step definition reads like scenario coordination. It does not know how the login page is implemented internally.
Page Object Example
public class LoginPage {
private WebDriver driver = DriverFactory.getDriver();
private By txtUsername = By.id("username");
private By txtPassword = By.id("password");
private By btnLogin = By.id("login");
private By dashboard = By.id("dashboard");
public void open() {
driver.get(ConfigReader.getProperty("url"));
}
public void login(String username, String password) {
driver.findElement(txtUsername).sendKeys(username);
driver.findElement(txtPassword).sendKeys(password);
driver.findElement(btnLogin).click();
}
public boolean isDashboardDisplayed() {
return driver.findElement(dashboard).isDisplayed();
}
}
The Page Object owns Selenium details. It exposes meaningful methods that can be reused by many scenarios.
One Page, One Class
A simple rule is one Page Object per page or major reusable component. A large application may have LoginPage, DashboardPage, CustomerPage, OrderPage, PaymentPage, and ReportsPage. Reusable sections such as headers, menus, dialogs, and tables can become Page Components.
This prevents one massive Page Object from collecting hundreds of unrelated methods.
Locators Belong in Page Objects
Locators should not appear in feature files or step definitions. If a locator is repeated in multiple step classes, maintenance becomes painful. Page Objects centralize locators so UI changes have a smaller impact.
Business Methods
Page Object methods should usually express user intent. Prefer methods such as login(), searchProduct(), createCustomer(), and placeOrder(). Avoid exposing every tiny click and typing action unless the page component truly needs that level of control.
Business-oriented methods make step definitions easier to read and help keep Gherkin focused on behavior.
Waits Inside Page Objects
Waits should live in Page Objects or reusable utilities. A Page Object method can wait for an element to be visible or clickable before interacting with it. This creates consistent synchronization across the framework.
Putting waits directly in step definitions leads to duplication and makes scenarios harder to maintain.
Assertions and Return Values
Some teams put assertions inside Page Objects using methods like verifyDashboard(). Larger frameworks often prefer Page Objects to return state, such as isDashboardDisplayed(), and keep assertions in step definitions. Both approaches can work, but the team should be consistent.
Common Mistakes
Common mistakes include Selenium code in step definitions, duplicate locators, very large Page Objects, hardcoded test data, Page Objects calling step definitions, and low-level methods that make scenarios procedural. Another mistake is building Page Objects without waits, which causes flakiness when pages update dynamically.
Best Practices
Create one Page Object per page or major component. Keep locators and UI actions inside Page Objects. Keep step definitions thin. Use business-oriented page methods. Centralize WebDriver access through Driver Factory. Manage browser lifecycle with hooks. Place waits inside Page Objects or utilities. Reuse Page Objects across feature files.
Interview-Ready Summary
Page Object Model separates UI interaction logic from test logic. In Cucumber frameworks, feature files describe behavior, step definitions coordinate execution, and Page Objects perform Selenium operations. This improves readability, reusability, and maintainability, especially in enterprise automation frameworks.