Built-in PageObject Class
Relevant source files
The following files were used as context for generating this wiki page:
The Built-in PageObject class serves as the fundamental base for the library's Page Object Model (POM) implementation. It is designed specifically for nested controls and components within a web page, providing a structured way to encapsulate locators, wait logic, and assertions. While the library supports plain classes, the PageObject class offers an "out-of-the-box" layer that integrates deeply with decorator-driven selector composition.
This class acts as a bridge between high-level component logic and raw Playwright Locator actions. It ensures that selector chains remain lazy, resolving only when accessed, while providing a standardized API for common automation tasks like waiting for visibility or verifying element state.
Sources: src/page-objects/PageObject.ts:28-35, README.md:126-133, skills/playwright-page-object/SKILL.md:23-31
Architecture and Core Logic
The PageObject architecture relies on three primary properties: the Playwright Page instance, a root locator (providing the parent context), and a selector function. The selector function is typically injected by child decorators like @Selector to resolve a specific element relative to the root.
Hierarchy and Lifecycle
The library distinguishes between root-level containers and nested components.
- RootPageObject: Used for top-level classes instantiated directly with a
Page. - PageObject: Reserved for nested components. It should never be decorated with
@RootSelector.
The diagram shows the inheritance structure where PageObject is the base for nested controls.
Sources: src/page-objects/PageObject.ts:44-50, README.md:144-149, skills/playwright-page-object/SKILL.md:40-45
Lazy Locator Resolution
The primary mechanism for element access is the $ getter (and the protected locator getter). These do not store a static locator; instead, they execute the selector function against the current root every time they are called. This ensures that if the DOM changes or the parent is re-rendered, the locator remains fresh.
Key Methods and API
The PageObject class provides a suite of helpers to simplify test code and reduce boilerplate.
Wait Helpers
These methods wrap Playwright assertions to provide a cleaner async API for synchronization.
| Method | Description | Internal Playwright Mapping |
|---|---|---|
waitVisible() | Waits for the element to become visible | expect(loc).toBeVisible() |
waitHidden() | Waits for the element to become hidden | expect(loc).toBeHidden() |
waitText(text) | Waits for exact text or regex match | expect(loc).toHaveText(text) |
waitValue(val) | Waits for an input to have a specific value | expect(loc).toHaveValue(val) |
waitCount(n) | Waits for a specific number of matching elements | expect(loc).toHaveCount(n) |
waitChecked() | Waits for a checkbox or radio to be checked | expect(loc).toBeChecked() |
Sources: src/page-objects/PageObject.ts:133-176, README.md:162-171
Custom State Logic (Props)
The class includes specialized methods for interacting with modern framework (React/Vue) internal states represented as data attributes.
- waitProp(name, value): Waits for a
data-prop-nameattribute to equal a value. - waitPropAbsence(name, value): Waits for the absence or change of a specific prop value.
Sources: src/page-objects/PageObject.ts:186-210, src/tests/page-objects/PageObject.spec.ts:189-215
Assertions
The .expect() method provides access to Playwright's assertion engine, bound to the current locator. It supports optional "soft" assertions that allow the test to continue on failure.
Sources: src/page-objects/PageObject.ts:222-233, README.md:173-177
Context Cloning and Nesting
A critical feature of PageObject is the ability to create new instances dynamically through cloneWithContext(). This is used by decorators to instantiate nested components while passing down the resolved locator of the parent as the new root.
If a subclass implements a custom constructor that deviates from the standard (page, root, selector) signature, it must override cloneWithContext to ensure the internal composition logic still works.
Sources: src/page-objects/PageObject.ts:120-128, src/tests/page-objects/PageObject.advanced.spec.ts:82-104, skills/playwright-page-object/SKILL.md:58-61
Implementation Example
The following snippet demonstrates a typical implementation of a nested control using the built-in PageObject class features:
import { PageObject, SelectorByText } from "playwright-page-object";
class ModalControl extends PageObject {
// Nested PageObject composition
@SelectorByText("Confirm")
accessor ConfirmButton = new PageObject();
async confirm() {
await this.waitVisible(); // Built-in wait
await this.ConfirmButton.$.click(); // Raw locator access via $
}
}
Sources: src/page-objects/PageObject.ts:38-43, README.md:154-160
Summary
The Built-in PageObject Class provides a robust foundation for building maintainable Playwright test suites. By encapsulating locator resolution, lifecycle management (cloning), and common automation actions (waits/assertions), it allows developers to focus on the semantic logic of their UI components rather than the underlying selector implementation. It is the recommended base for any component that needs to expose reusable actions or integrated assertions.