Quality Engineering: Playwright Page Object Generation
Priority: P1 (HIGH)
Input
A web-lane scenario block from docs/srs/test-plan-[slug].md (Steps, Expected, @AC-n) plus the resolved SELECTOR_GAPS for that screen. Generate from the plan, never from a live DOM crawl alone: the plan says which elements matter.
Layout
- One file per screen:
tests/pages/<screen>.page.ts, class<Screen>Page(e.g.CheckoutPage). - One locator getter per element the plan touches, named after the element (
submitButton,emailInput). - One action method per plan step verb (
fillShipping(data),submit()); actions returnvoidor the next page object. - A
pagesfixture intests/fixtures.tsexposes every page object; specs importtestfrom there, never from@playwright/testdirectly.
Locator Rules
Follow the web ladder in quality-engineering-selector-stability: getByRole / getByLabel first, then getByTestId using the <screen>-<element>-<role> id, then attribute CSS. Never XPath, nth, text on translated strings, or generated class names. When the element has no stable locator, do not invent one: record it as a selector gap for specialist-testid-inserter.
No Assertions in Page Objects
Page objects expose state (orderId(), isVisible()), specs assert on it. An expect inside a page object hides the assertion from the scenario and breaks reuse across positive and negative cases.
Workflow
- Read the scenario block and the screen's existing page object, if any; extend rather than duplicate.
- Map each plan step to an existing or new action method; map each
Expectedto a state getter. - Write locators per the ladder; list unresolved elements under
Selector Gapsin the output. - Register the page object in the
pagesfixture. - Run
npx tsc --noEmit -p tests(or the repo's typecheck) and the seed spec once.
Anti-Patterns
- No assertions in page objects:
expectbelongs in the spec. - No DOM-crawl page objects: a class with forty getters nobody's scenario uses is noise, not coverage.
- No duplicate page object: search
tests/pages/before creating; extend the existing class. - No raw
pagein specs: every interaction goes through a page object or the seed. - No renamed test ids: ids are a public contract; a rename is a selector gap, not a refactor.
References
- Page Object Template
- Fixture Wiring
- Playwright MCP Authoring