Intermediate
Chapter 10 · 12 min read
Page Object Model with Cucumber
Integrate the Page Object pattern with Cucumber step definitions — keep steps thin, delegate to page objects, and share state via dependency injection.
POM + Cucumber — Clean Architecture
Step definitions should be thin orchestrators. All page interactions belong in Page Objects. This separation means when the UI changes, you update one page class — not dozens of step files.
Sharing State Between Steps
In Java, use Dependency Injection (PicoContainer or Spring) to share state (like the WebDriver) across step definition classes. In Python, Behave's context object serves as the shared state container.
TestContext.java
package com.bdd.course.context;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import com.bdd.course.pages.LoginPage;
import com.bdd.course.pages.HomePage;
// Shared state via dependency injection (PicoContainer)
// Add: cucumber-picocontainer dependency in pom.xml
public class TestContext {
private WebDriver driver;
private LoginPage loginPage;
private HomePage homePage;
public WebDriver getDriver() {
if (driver == null) {
driver = new ChromeDriver();
driver.manage().window().maximize();
}
return driver;
}
public LoginPage getLoginPage() {
if (loginPage == null) {
loginPage = new LoginPage(getDriver());
}
return loginPage;
}
public HomePage getHomePage() {
if (homePage == null) {
homePage = new HomePage(getDriver());
}
return homePage;
}
public void tearDown() {
if (driver != null) {
driver.quit();
driver = null;
}
}
}
LoginStepsPOM.java
package com.bdd.course.stepdefinitions;
import io.cucumber.java.en.*;
import com.bdd.course.context.TestContext;
import com.bdd.course.pages.LoginPage;
import com.bdd.course.pages.HomePage;
import org.testng.Assert;
public class LoginStepsPOM {
// Injected by PicoContainer automatically
private final TestContext context;
public LoginStepsPOM(TestContext context) {
this.context = context;
}
@Given("the user is on the login page")
public void userOnLoginPage() {
context.getDriver().get("https://example.com/login");
}
@When("the user enters username {string} and password {string}")
public void enterCredentials(String user, String pass) {
context.getLoginPage()
.enterUsername(user)
.enterPassword(pass);
}
@When("the user clicks the login button")
public void clickLogin() {
context.getLoginPage().clickLogin();
}
@Then("the user should be redirected to the dashboard")
public void verifyDashboard() {
Assert.assertTrue(
context.getHomePage().isDashboardDisplayed());
}
@Then("the welcome message should display {string}")
public void verifyWelcome(String expected) {
Assert.assertEquals(
context.getHomePage().getWelcomeMessage(), expected);
}
}
pages/login_page.py
# pages/login_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class LoginPage:
URL = "https://example.com/login"
USERNAME = (By.ID, "username")
PASSWORD = (By.ID, "password")
LOGIN_BTN = (By.CSS_SELECTOR, "button[type='submit']")
ERROR_MSG = (By.CSS_SELECTOR, ".error-message")
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def navigate(self):
self.driver.get(self.URL)
return self
def enter_username(self, username):
el = self.wait.until(EC.visibility_of_element_located(self.USERNAME))
el.clear()
el.send_keys(username)
return self
def enter_password(self, password):
el = self.driver.find_element(*self.PASSWORD)
el.clear()
el.send_keys(password)
return self
def click_login(self):
self.driver.find_element(*self.LOGIN_BTN).click()
return self
def get_error_message(self):
return self.driver.find_element(*self.ERROR_MSG).text
def login_as(self, username, password):
return self.enter_username(username).enter_password(password).click_login()
login_steps_pom.py
# features/steps/login_steps_pom.py
from behave import given, when, then
from pages.login_page import LoginPage
from pages.home_page import HomePage
@given('the user is on the login page')
def step_on_login(context):
context.login_page = LoginPage(context.driver)
context.login_page.navigate()
@when('the user enters username "{user}" and password "{pwd}"')
def step_enter_creds(context, user, pwd):
context.login_page.enter_username(user).enter_password(pwd)
@when('the user clicks the login button')
def step_click_login(context):
context.login_page.click_login()
context.home_page = HomePage(context.driver)
@then('the user should be redirected to the dashboard')
def step_verify_dashboard(context):
assert context.home_page.is_dashboard_displayed()
@then('the welcome message should display "{expected}"')
def step_verify_welcome(context, expected):
assert context.home_page.get_welcome_message() == expected
Cucumber BDD
Intermediate
Page Object Model with Cucumber
Written by PV
© 2026 All Rights Reserved