Chapter 13Lesson 03~185 minutes

Page Object, Page Component, Screenplay, and Test Abstraction Patterns: Configuration, Design Patterns, and Trade-Offs

Abstraction patterns are design choices, not a maturity ladder. This lesson evaluates when direct code, Page Objects, components, task layers, fluent APIs, and Screenplay-style structures improve maintenance—and when they create ceremony or hide the state needed for diagnosis.

Trade-offsCompositionAssertionsFluent APIsSuite scale

Learning objectives

  • Choose between direct test code and Page Objects based on duplication, change frequency, and diagnostic needs.
  • Use component composition to prevent giant page classes and DOM-shaped inheritance hierarchies.
  • Separate action methods from state-query methods so assertions retain explicit meaning.
  • Compare fluent chains with explicit steps and Screenplay ceremony with large-suite scalability.
  • Keep browser/session/test-data/evidence infrastructure out of page abstractions.
  • Use a worked decision table that connects abstraction choices to observable CI behavior and maintenance cost.

1. Start with the change you want to contain

The right abstraction is the smallest boundary that contains a recurring kind of change. If three tests repeat the same locator and readiness rule, a Page Object may reduce real duplication. If a single experiment has one interaction, a page class may add more code than it removes. If a multi-page business action is repeated across dozens of scenarios, a task/domain layer may keep that workflow out of multiple page classes.

2. Direct test code versus Page Objects

The following table organizes the key choices and evidence for Direct test code versus Page Objects. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Context Direct Selenium can be reasonable Page Object is usually stronger
tiny exploratory check one-off, short-lived, no repeated page mechanics not necessarily needed
growing regression suite duplication becomes visible quickly centralizes page services/locators/waits
UI with frequent locator/layout change change fans across tests change localized to page/component boundary
diagnostic prototype raw commands reveal mechanics clearly introduce after behavior is understood

Do not begin by generating a class for every URL. Model meaningful services and reusable mechanics after the behavior is understood.

3. Components versus God page classes

A page with product cards, navigation, filters, dialogs, and tables should not necessarily expose every internal locator from one class. Page Components make ownership smaller. The page composes them; components may themselves compose smaller regions when that maps to stable UI responsibilities.

Symptom God page risk Component response
hundreds of unrelated locators every UI change touches one conflict-heavy file move cohesive regions into components
same navbar repeated across pages duplicate locators/actions shared NavigationBar component
component-specific rerender page caches stale descendants reacquire component at page boundary
DOM inheritance mirrored in classes fragile coupling to markup nesting prefer object composition

4. Separate actions from state queries

Action methods mutate browser/AUT state: add(), filter_products(), submit(). Query methods expose observable state: price_text(), cart_count(), error_message(). Keeping this distinction visible makes assertions easier to place and failures easier to explain.

# Page/component layer
page.filter_products("Cable")          # action
names = [p.name() for p in page.products()]  # query

# Test layer
assert names == ["Fiber Cable"]

5. Assertion placement is a diagnostic choice

The following table organizes the key choices and evidence for Assertion placement is a diagnostic choice. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Placement Advantage Risk / rule
test/scenario failure meaning is explicit and close to intent preferred for business expectations
page constructor/loaded guard fails early when abstraction is used on wrong page check contract/readiness, not business outcome
task can verify action completion before returning do not hide scenario assertions inside task
component query reuses observation logic return state rather than assert hidden expectations

6. Fluent APIs versus explicit steps

A fluent API can make a stable linear workflow readable, but long chains can hide which action changed context or failed. Selenium’s guidance treats fluent style as an option, not a requirement. Prefer a chain only when each returned object/state is unambiguous and failure reporting identifies the exact operation.

# Explicit style: easiest to inspect while learning/diagnosing.
page.filter_products("Cable")
cable = page.product_named("Fiber Cable")
cable.add()

# A fluent style can be acceptable if each method has a clear contract.
# page.filter_products("Cable").add_product("Fiber Cable")

7. Screenplay ceremony versus scalability

The following table organizes the key choices and evidence for Screenplay ceremony versus scalability. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Suite shape Likely fit Reason
5–20 simple page-focused tests Page Objects + components small mental model and low ceremony
many repeated cross-page business workflows add task/domain layer workflow changes localized outside individual pages
large multi-role domain with shared tasks/questions consider Screenplay-style actor/task/question model strong ubiquitous language and reuse
team unfamiliar with pattern adopt incrementally abstraction is harmful if only one maintainer understands it

Screenplay-style structure is not a substitute for solid locators, waits, session isolation, or evidence. It is an organizational layer above those mechanics.

8. Inheritance versus composition

Use inheritance only for genuinely stable, small behavioral contracts. A giant BasePage containing every wait, click, API call, screenshot, browser option, and navigation helper creates invisible coupling. DOM containment is naturally modeled by composition: CatalogPage has ProductCards; it does not inherit from them.

9. Keep configuration layers separate

The following table organizes the key choices and evidence for Keep configuration layers separate. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Concern Correct home Why
browser/profile/options driver factory / test infrastructure session configuration is not page behavior
base URL/environment environment config / test setup do not compile environment identity into page classes
synthetic data creation fixture/API setup layer page object should not own shared data lifecycle
locators + page readiness Page Object / Page Component UI implementation boundary
business workflow spanning views task/domain layer when repeated keeps page classes cohesive
business assertion test/scenario preserves intent/failure meaning
screenshot/report/CI artifact evidence/test-runner layer cross-cutting concern and privacy policy

10. Worked design decision

Suppose a catalog suite has 60 tests, five browsers in CI, repeated add-to-cart flows, a shared navigation bar, and a frequently rerendered product grid. A reasonable design is:

  1. CatalogPage owns filter/grid locators and returns fresh ProductCard components.
  2. ProductCard owns card-local name/price/add mechanics.
  3. NavigationBar is a reusable component shared by pages.
  4. AddProductToCart becomes a task because the workflow is reused.
  5. Scenario assertions remain in tests.
  6. Driver factory owns browser matrix/options; test hooks own screenshots and capabilities evidence.
  7. Adopt an actor/task/question vocabulary only if multiple user roles and many shared domain tasks justify it.

11. Maintainability, portability, performance, and security trade-offs

The following table organizes the key choices and evidence for Maintainability, portability, performance, and security trade-offs. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Dimension Healthy abstraction effect Failure mode when overdone
maintainability one UI change touches one page/component contract layers multiply without reducing duplication
diagnostics test intent + page mechanics remain traceable helpers swallow exceptions or hide assertions
portability browser config stays outside pages vendor options leak into page constructors
execution time reusable waits target real conditions generic helper waits add unnecessary timeout budget
privacy/security evidence/account/profile policy centralized page helpers capture broad screenshots/logs or secrets implicitly
parallel CI session/test state stays per test singleton pages/drivers become shared mutable state

12. Summary and next step

Choose abstractions by change ownership and diagnostic clarity, not by pattern prestige. Start with page services and components; introduce tasks when workflows repeat; use Screenplay-style structure when domain scale earns the extra vocabulary. Lesson 4 diagnoses what happens when these boundaries collapse.

Knowledge check

When is direct Selenium code preferable to a Page Object?

Why separate action methods from query methods?

What is the main risk of a giant BasePage?

When does a task layer earn its cost?

What remains true no matter which abstraction pattern is chosen?

Next lesson

Page Object, Page Component, Screenplay, and Test Abstraction Patterns: Diagnostics, Failure Modes, and Production Practices

Continue with Page Object, Page Component, Screenplay, and Test Abstraction Patterns: Diagnostics, Failure Modes, and Production Practices. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was rechecked against current Selenium primary documentation on 2026-08-28. Mandatory examples pin Selenium Python 4.47.0 and Python 3.10+, use a supported locally installed Chromium-family browser with Selenium Manager, and target only loopback fixtures. Page Object, Page Component, task/DSL, and Screenplay-style structures are test-architecture patterns rather than capabilities negotiated with the browser. The mandatory path uses Python standard-library unittest for the small suite so no external test-architecture framework is required. The Screenplay-style example is intentionally framework-free and remains an organizational layer over ordinary Selenium WebDriver.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.