Child Decorators Reference
Relevant source files
The following files were used as context for generating this wiki page:
Child decorators in playwright-page-object are used to define and resolve Playwright locators relative to a parent context. They transform class accessors into lazy-evaluated Playwright Locator instances or custom control objects. By decorating accessors, developers can maintain a typed, hierarchical structure that mirrors the application's DOM without manually chaining page.locator() calls.
Sources: README.md:1-25, skills/playwright-page-object/SKILL.md:14-25
Architecture and Data Flow
The child decorator system operates on a lazy-resolution model. When an accessor is decorated, it does not immediately resolve the selector; instead, the resolution occurs only when the property is accessed at runtime. The decorators use the parent's root locator as the base and apply the specific child selector logic to derive the final element.
The flow shows how a child decorator takes the parent context and maps it to a specific Playwright locator strategy, optionally wrapping it in a class.
Sources: README.md:120-135, src/page-objects/PageObject.ts:60-85
Resolution Logic
Every child decorator requires a "root context" which is typically established by a @RootSelector on the containing class. If the accessor is declared within a class extending PageObject, it utilizes the this.root property to perform the relative search.
Sources: src/page-objects/PageObject.ts:70-80, skills/playwright-page-object/SKILL.md:46-52
Child Decorator API
Child decorators map directly to Playwright's Locator API. They are designed to be used with the ECMAScript accessor keyword.
| Decorator | Playwright Mapping | Description |
|---|---|---|
@Selector(id) | getByTestId(id) | Locates element by its test ID attribute. |
@Selector() | Identity | Returns the root locator itself (identity selector). |
@ListSelector(id) | getByTestId(new RegExp(id)) | Locates elements matching a partial test ID via regex. |
@ListStrictSelector(id) | getByTestId(id) | Exact match for collections of test IDs. |
@SelectorByRole(role, options) | getByRole(role, options) | Locates elements by ARIA role and attributes. |
@SelectorByText(text) | getByText(text) | Locates elements by visible text content. |
@SelectorByLabel(label) | getByLabel(label) | Locates elements by their associated label. |
@SelectorByPlaceholder(p) | getByPlaceholder(p) | Locates input elements by placeholder text. |
@SelectorByAltText(alt) | getByAltText(alt) | Locates elements (like images) by alt text. |
@SelectorByTitle(title) | getByTitle(title) | Locates elements by their title attribute. |
@SelectorBy(fn) | Custom logic | Uses a user-provided function (root) => Locator. |
Sources: README.md:210-235, src/tests/decorators/selectors.spec.ts:100-150, src/index.ts:1-25
Output Shapes
Child decorators are polymorphic in their return types based on how they are declared and the arguments provided to the decorator.
1. Raw Locator Output
When the accessor is typed as Locator, the decorator returns the raw Playwright object. This is ideal for minimal abstraction.
@Selector("PromoCodeInput")
accessor PromoCodeInput!: Locator;
Sources: README.md:75-85, src/tests/decorators/selectors.spec.ts:38-45
2. External Controls
Decorators accept a trailing argument (either a constructor or a factory function) to wrap the resolved Locator in a custom class that does not necessarily inherit from PageObject.
// Using a constructor
@Selector("SubmitBtn", MyButtonControl)
accessor SubmitButton!: MyButtonControl;
// Using a factory
@Selector("Input", (loc) => new CustomInput(loc, "custom-config"))
accessor InputField!: CustomInput;
Sources: README.md:90-110, src/tests/decorators/selectors-external.spec.ts:45-75
3. Built-in PageObject Layer
If the accessor is initialized with a new PageObject or ListPageObject, the decorator utilizes the cloneWithContext method to bind the new instance to the resolved locator.
This sequence illustrates how PageObject instances are lazily cloned and bound to their specific locators upon access.
Sources: src/page-objects/PageObject.ts:104-110, src/tests/page-objects/PageObject.advanced.spec.ts:80-95, src/tests/decorators/selectors.spec.ts:60-75
Custom Selection Logic
The @SelectorBy decorator allows for complex selection logic that isn't covered by standard Playwright getBy... methods. It receives the current root and the initial value of the accessor.
@SelectorBy((root, value) => root.locator(".custom-class").nth(0))
accessor CustomElement = "initial-value";
Sources: src/tests/decorators/selectorBy.spec.ts:25-45, src/index.ts:13
Summary of Usage Rules
- Accessor Keyword: All child decorators must be used with the
accessorkeyword to allow the library to intercept getter/setter logic. - Root Requirement: Child decorators must exist within a class that has a
@RootSelectoror a definedrootlocator to avoid resolution errors. - Lazy Resolution: Accessors are re-evaluated on every access, ensuring that if the DOM changes or the parent root is updated, the child locator remains accurate.
- Context Preservation: When using
PageObjectsubclasses with custom constructors, thecloneWithContext()method must be overridden to ensure parameters are preserved during nesting.
Sources: skills/playwright-page-object/SKILL.md:40-60, src/page-objects/PageObject.ts:65-75, src/tests/page-objects/PageObject.advanced.spec.ts:110-125