Q2 of 37 · Selenium

Explain the Page Object Model with a concrete example.

SeleniumMidseleniumpage-objectsdesign-patternsarchitecture

Short answer

Short answer: Page Object Model wraps each page (or significant component) as a class that exposes user-level actions and hides locators. Tests stay readable, and a CSS change is fixed in one file instead of fifty.

Detail

The Page Object Model is the canonical pattern for keeping Selenium suites maintainable. The idea: for each page in the application — login, dashboard, checkout — write a class. The class owns the locators (private), exposes user-level actions (login(email, password), addToCart(item)), and returns either void or the next page object so calls can chain naturally.

The win is single point of change. When the login form gets redesigned and #username becomes [data-test=email], you edit LoginPage.java once. Without page objects, that locator is duplicated across every spec that touches login.

Two refinements worth mentioning. Component objects apply the same idea to repeating UI fragments — a navbar, a row in a table — so a Navbar object can be composed into many page objects. Loadable / fluent style returns the next page from each action: new LoginPage(driver).login(...).goToDashboard() reads like the user's journey and gives the type system a chance to catch impossible navigation.

What page objects should not contain: assertions. Assertions belong in tests so failures point to the test's intent, not to a generic helper. Page objects expose state ("is the error banner visible?") that tests assert against.

// EXAMPLE

LoginPage.java

public class LoginPage {
    private final WebDriver driver;
    private final WebDriverWait wait;

    private final By emailField = By.cssSelector("[data-test=email]");
    private final By passwordField = By.cssSelector("[data-test=password]");
    private final By submitButton = By.cssSelector("[data-test=submit]");
    private final By errorBanner = By.cssSelector("[data-test=login-error]");

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    public DashboardPage loginAs(String email, String password) {
        driver.findElement(emailField).sendKeys(email);
        driver.findElement(passwordField).sendKeys(password);
        driver.findElement(submitButton).click();
        return new DashboardPage(driver);
    }

    public boolean isErrorVisible() {
        try {
            return wait.until(ExpectedConditions.visibilityOfElementLocated(errorBanner))
                       .isDisplayed();
        } catch (TimeoutException e) {
            return false;
        }
    }
}

// WHAT INTERVIEWERS LOOK FOR

Understanding the maintenance argument, awareness of component objects, and knowing assertions belong in tests — not in page objects. Bonus for fluent/chainable style.

// COMMON PITFALL

Putting assertions inside page object methods, or making page objects so granular that they expose individual locators rather than user actions.