liveBook · Manning

Page object

As explained in BDD in Action, Second Edition

A page object is a test automation abstraction that encapsulates a web page's structure and interaction details while exposing readable operations and state.

When a UI change forces edits across many acceptance tests, the tests may know too much about the page’s HTML. A page object puts element locators and interaction code behind readable operations. Tests can then say what a user does or what the interface shows without repeating how to find each element. section 11.2 section 11.3

public class LoginPage {
    private static final By EMAIL_FIELD = By.id("email");               #1
    private static final By PASSWORD_FIELD = By.id("password");         #1
    private static final By LOGIN_BUTTON = By.id("login-button");       #1
 
    private final WebDriver driver;                                     #2
 
    public LoginPage(WebDriver driver) {                                #3
        this.driver = driver;
    }
 
    public void open() {                                                #4
        driver.get("http://localhost:3000/login");
    }
 
    public void signinWithCredentials(String email, String password) {  #5
        driver.findElement(EMAIL_FIELD).sendKeys(email);                #6
        driver.findElement(PASSWORD_FIELD).sendKeys(password);          #6
        driver.findElement(LOGIN_BUTTON).click();                       #6
    }
}

The LoginPage class keeps its locators together and exposes open() and signinWithCredentials() instead of making each test manipulate the email field, password field, and button. section 11.2

Keep the boundary between test intent and UI implementation clear:

  • Model a significant page component when a whole-page class would become unwieldy; a shared menu bar is a candidate. section 11.3.2
  • Offer operations at a useful business level. A sign-in method can group entering credentials and clicking the button; separate field methods may suit tests of incomplete search criteria. section 11.3.4
  • Return state in business-friendly values, such as a Boolean indicating whether search is enabled or a list of missing field names. Do not return WebElement objects. section 11.3.3 section 11.3.5
  • Keep incidental waits inside interaction methods, but leave assertions in the test or step definition. The page object reports what it sees; the test decides whether that is correct. section 11.3.6 section 11.3.7

Search form with missing fields

A flight-search scenario tries criteria with no departure, destination, or travel class. A SearchForm object can enter those values, report whether the Search button is enabled, and return the names of fields marked invalid. The step definition asserts which field should be reported, without depending on its CSS selector or display color. section 11.3.4 section 11.3.5

Page objects work well for small applications, but large classes can become fragile when they mix business tasks with detailed UI mechanics. An action or domain-specific-language layer can sit between step definitions and interactions, allowing some steps to use APIs rather than the UI. In a Screenplay-style design, a Lean Page Object has a narrower job: describe a widget’s elements and state, while tasks and interactions express behavior. section 11.4 section 15.2.3

Listing 15.9 Lean Page Object representing the toaster widget
import { By, CssClasses, PageElement } from '@serenity-js/web'
import { QuestionAdapter } from '@serenity-js/core'
 
export class Toaster {
    private static component = () =>
        PageElement.located(By.css(`.ngx-toastr`))
            .describedAs('toaster')
    static message = () =>
        PageElement.located(By.css(`.toast-message`))
            .of(Toaster.component())                                     #1
            .describedAs('message')
 
    static status = () =>
        CssClasses.of(Toaster.component())                               #2
            .filter(cssClass => cssClass.startsWith('toast-'))           #3
            .map(cssClass => cssClass.replace('toast-', ''))
            .slice(0, 1)[0]
            .describedAs('toaster status') as QuestionAdapter<string>    #4
}

The Lean Page Object identifies a notification widget’s message and translates its CSS classes into a meaningful success or error status. section 15.2.3

How BDD in Action, Second Edition covers it

How deep it goes
Works through locators, component scope, actions, state, waits, and assertion boundaries, then examines scaling limits and a lean variant.
Examples
Uses a login page, flight-search form, shared menu bar, and notification widget to show operations and state.
What it assumes
Assumes basic Selenium WebDriver interaction and develops the organization of UI test code from that starting point.
What you can do after
Build it from scratch by centralizing UI details, exposing readable methods and state, and keeping assertions in tests.
How it connects
Connects page component objects, Selenium WebDriver, step definitions, action classes, and the Screenplay Pattern.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of BDD in Action, Second Edition. The section links point to the parts of the book it draws on.