Decorator Unit Tests
Relevant source files
The following files were used as context for generating this wiki page:
The Decorator Unit Tests comprise a suite of technical verifications ensuring that TypeScript decorators correctly map class accessors to Playwright Locator logic. These tests validate the establishment of root contexts via root decorators and the subsequent resolution of child selectors relative to those roots. The scope includes testing for built-in PageObject types, external control classes, and raw Playwright locators.
These tests ensure that the framework's core mental model—where root decorators establish locator context and child decorators resolve relative selectors—is enforced across various implementation styles, including plain classes and the built-in POM layer.
Root Selector Architecture
Root decorators are responsible for binding a top-level class to a Playwright Page and establishing a base Locator. Tests verify that these decorators override the class constructor to inject locator resolution logic.
Context Establishment
Tests confirm that @RootSelector() and its variants (e.g., @RootSelectorByRole, @RootSelectorByText) correctly call Playwright's getBy... methods on the page's body or specific test IDs. A critical requirement validated is that the first constructor argument must be a Playwright Page object; otherwise, the system throws an explicit error.
The diagram shows the validation logic performed by root decorators during class instantiation.
Sources: src/tests/decorators/rootSelectors.spec.ts:47-75, README.md:95-103
Root Decorator Mappings
The following table summarizes the mappings between decorators and Playwright methods as verified in the unit tests:
| Decorator | Playwright Method | Test Verification |
|---|---|---|
@RootSelector(id) | getByTestId(id) | Calls getByTestId with the provided string. |
@RootSelector() | locator("body") | Uses the body as the identity selector. |
@RootSelectorByText(text) | getByText(text) | Validates text-based root matching. |
@RootSelectorByRole(role, options) | getByRole(role, options) | Validates ARIA role and name filtering. |
@RootSelectorByLabel(label) | getByLabel(label) | Validates form label association. |
Sources: src/tests/decorators/rootSelectors.spec.ts:77-156, README.md:231-241
Child Selector Resolution
Child decorators resolve locators relative to the context established by the root. Tests ensure that these selectors are lazy—re-evaluating on every access—and correctly handle nested relationships.
Nested Composition Logic
When an accessor is decorated with @Selector, the unit tests verify that the framework retrieves the parent's locator and chains the child selector onto it. This is tested for both PageObject instances and raw Locator values.
This sequence illustrates the lazy resolution of child selectors during a property access.
Sources: src/tests/decorators/selectors.spec.ts:182-225, src/tests/page-objects/PageObject.spec.ts:58-65
External Control Integration
Tests in selectors-external.spec.ts verify that decorators can instantiate non-framework classes (external controls). The framework can use a trailing constructor or a factory function to create these objects, passing the resolved Locator as an argument.
- Constructor Path:
@Selector("id", ExternalButton)createsnew ExternalButton(locator). - Factory Path:
@Selector("id", (loc) => new Custom(loc, "config"))allows custom initialization.
Sources: src/tests/decorators/selectors-external.spec.ts:31-85, README.md:129-155
Specialized Selector Behaviors
Custom Logic with @SelectorBy
The @SelectorBy(fn) decorator allows for arbitrary locator logic. Tests verify that the provided function receives the parent locator and the current accessor value, allowing it to return a transformed locator or a completely different object.
Sources: src/tests/decorators/selectorBy.spec.ts:24-42
List Selectors
Selects are categorized into strict and regex-based matching:
@ListSelector(id): Verified to usenew RegExp(id)for fuzzy matching of repeated elements.@ListStrictSelector(id): Verified to use exact string matching viagetByTestId(id).
Sources: src/tests/decorators/selectors.spec.ts:35-68, README.md:214-220
PageObject Base Class Validation
Tests for the PageObject base class ensure that the built-in POM layer functions correctly. Key behaviors include:
- Lazy Initialization: The
locatorgetter throws an error if decorators were skipped, ensuring developers are alerted to configuration issues. - Context Cloning: The
cloneWithContextmethod is tested to ensure that nested objects receive the correct page and root when parents are instantiated. - Wait Helpers: Methods like
waitVisible()andwaitCount()are verified to correctly bridge to Playwright'sexpectAPI.
The hierarchy tested ensures RootPageObject serves as the entry point while PageObject handles nesting.
Sources: src/tests/page-objects/PageObject.spec.ts:76-130, src/page-objects/PageObject.ts:108-115
Conclusion
The Decorator Unit Tests provide a robust validation layer for the framework's locator composition engine. By covering root establishment, child nesting, external control instantiation, and the built-in PageObject API, these tests ensure that the decorator-driven graph remains reliable, typed, and lazy. This architecture allows for incremental adoption while maintaining technical accuracy across different selector strategies.