Skip to content

PageObject

PageObject is the base class for nested controls. Use it as the initializer for a decorated accessor:

@Selector("PromoCode")
accessor PromoCode = new PageObject();

For root-level page objects, use RootPageObject instead.

.$

The raw Playwright Locator bound to this control’s resolved chain.

await checkout.PromoCode.$.fill("SAVE20");
await checkout.PromoCode.$.click();

Use whenever a built-in wait helper does not cover your case.

A getter that returns the underlying Page instance.

const page = checkout.PromoCode.page;
await page.keyboard.press("Escape");

Returns Playwright’s assertion API on .$. Accepts the same options as Playwright’s expect:

await control.expect().toBeVisible();
await control.expect({ soft: true }).toHaveText("Click me");
await control.expect({ message: "Apply must be enabled" }).toBeEnabled();
MethodAccepts
waitVisible()
waitHidden()
waitText(text)string | RegExp
waitValue(value)string | RegExp | number
waitCount(count)number
waitChecked()
waitUnChecked()
await control.waitVisible();
await control.waitText("Applied");
await control.waitText(/applied/i);
await control.waitValue(42); // coerced to "42"

waitValue accepts number and coerces with String(value) for convenience. Pass a RegExp for pattern matching.

For typed nested children, extend PageObject and add decorated accessors:

class CartItemControl extends PageObject {
@Selector("Name")
accessor Name = new PageObject();
@SelectorByRole("button", { name: "Remove" })
accessor RemoveButton = new PageObject();
async remove() {
await this.RemoveButton.$.click();
}
}

Use the subclass as an initializer:

@Selector("CartItem_1")
accessor FirstItem = new CartItemControl();

If your subclass has constructor arguments beyond the default, override cloneWithContext(root, selector). The library calls this on every access to bind the instance to its parent’s resolved scope.

class TimedItem extends PageObject {
constructor(readonly timeout: number) {
super();
}
cloneWithContext(root, selector) {
const next = new TimedItem(this.timeout);
return next.attach(root, selector);
}
}

Most users do not need this — the default cloneWithContext covers the no-arg constructor case.

StaticReturns
PageObject.isClass(v)true if v is a class extending PageObject
PageObject.isInstance(v)true if v is an instance of PageObject

Used internally and exposed for advanced use cases (e.g., generic helpers that inspect accessor types).