Files
skills/docs/testkit/testing/testing-e2e/src/page-objects/page-object.md
2026-05-29 08:20:56 +01:00

3.4 KiB

page-object

(no submodules)

Purpose

PageObject is the abstract base class for Playwright Page Object Model implementations. It wires every subclass with a consistent navigate / waitForReady / findByRole / findByLabel / findByText surface so spec files stay declarative. Subclasses override the path and waitForReady specifics while inheriting the shared query conveniences.

Features

  • Abstract path: string — subclass declares the route
  • navigate(options?) — delegates to page.goto with the configured path
  • waitForReady(options?) — subclass overrides to assert page-specific readiness
  • Query helpers: findByRole, findByLabel, findByText — thin wrappers over page.getBy*
  • exactOptionalPropertyTypes-safe: timeout is forwarded only when set

Usage: Basic Example

import { PageObject } from "@suaveplan/testing-e2e/page-objects";

class LoginPage extends PageObject {
    public readonly path = "/login";
    public async waitForReady(): Promise<void> {
        await this.findByRole("heading", { name: /sign in/i });
    }
}

// spec:
const login = new LoginPage(page);
await login.navigate();
await login.waitForReady();

Usage: Advanced Example

import { PageObject } from "@suaveplan/testing-e2e/page-objects";
import { expect } from "@playwright/test";

class CheckoutPage extends PageObject {
    public readonly path = "/checkout";

    public async waitForReady({ timeoutMs }: { timeoutMs?: number } = {}): Promise<void> {
        const headingFinder = this.findByRole("heading", { name: /checkout/i });
        await expect(headingFinder).toBeVisible({
            ...(timeoutMs !== undefined ? { timeout: timeoutMs } : {}),
        });
    }

    public async enterCardNumber(number: string): Promise<void> {
        await this.findByLabel("Card number").fill(number);
    }

    public async submit(): Promise<void> {
        await this.findByRole("button", { name: /pay now/i }).click();
    }
}

// spec:
const checkout = new CheckoutPage(page);
await checkout.navigate({ timeoutMs: 10_000 });
await checkout.waitForReady();
await checkout.enterCardNumber("4242 4242 4242 4242");
await checkout.submit();

API Reference

abstract class PageObject

  • abstract readonly path: string
  • constructor(page: Page)
  • navigate(options?: { timeoutMs?: number }): Promise<void>
  • waitForReady(options?: { timeoutMs?: number }): Promise<void> — subclass override
  • findByRole(role, options?) → Locator
  • findByLabel(label) → Locator
  • findByText(text) → Locator

Implementation Notes

navigate calls page.waitForLoadState("domcontentloaded", waitOptions) where waitOptions is undefined when no timeout is supplied and { timeout } when one is — this conditional construction is required by exactOptionalPropertyTypes which forbids passing { timeout: undefined }. The class deliberately stays small; subclass-specific assertions belong on the subclass, not baked into a common helper that tries to anticipate every scenario.

Base Class

PageObject is the minimal base class for Playwright page-object-model helpers. It carries a page: Page reference, a baseUrl: string, and exposes goto(path?) / expectVisible(locator) / expectUrlMatches(regex) helpers that every subclass uses. Subclasses narrow the locator surface to the page's specific components and keep tests focused on flows rather than selectors.