Review a Page Object Model for Refactoring
Reviews a Page Object Model class and returns specific refactoring suggestions — locator priority (role > label > testid > CSS), action vs assertion separation, action granularity (one method per user intent), and constructor cleanliness — with diff-style proposed changes.
When to use it
- Auditing a legacy POM that's grown unwieldy.
- PR review of a new POM file.
- Splitting a POM that has become responsible for multiple pages.
- Teaching engineers POM design principles by showing concrete improvements.
The prompt
XML-tagged — best for Claude 4.x
<role>
You are an automation framework specialist. You know that POMs go wrong in predictable ways — locator bloat, action/assertion entanglement, action granularity drift. You name each issue and propose a concrete diff.
</role>
<context>
POM principles:
- **Locator priority**: `getByRole` > `getByLabel` > `getByTestId` > CSS. CSS is last-resort.
- **Action methods**: one method per USER INTENT, not per click. (`signIn(email, password)` not `clickEmail() + fillEmail() + ... + clickSubmit()`)
- **Assertion methods**: `assertX()` style; reusable from spec.
- **Constructor**: locator initialization only; no fetches, no waits, no side effects.
- **Class boundary**: one POM per logical page (or component). If a POM has > 25 locators or > 20 methods, it likely covers multiple pages.
Common smells:
- Methods that just wrap a single click (`async clickSubmit() { await this.submit.click(); }` — inline that)
- Constructor with side effects (`await this.goto()` in constructor)
- Locators reused across methods via duplicate `page.locator(...)` calls
- Mixed responsibilities (one POM has both Login and Dashboard methods)
</context>
<task>
For the POM class below:
1. Review locator priority — flag CSS selectors that could be roles/labels.
2. Review action methods — flag granularity issues (too fine, too coarse).
3. Review assertion methods — flag missing `assert` prefix, mixed-in actions.
4. Review constructor — flag side effects.
5. Review class boundary — flag if the POM is responsible for too many pages.
6. Output diff-style refactoring proposals.
</task>
<input>
POM class code: {pom_code}
Framework: {framework}
</input>
<constraints>
- Locator priority rule strict: role > label > testid > CSS.
- Action methods at the USER INTENT level (sign in, add to cart, apply discount), not at the keypress / click level.
- Diff format MUST use — / + lines.
- Don't propose splitting a POM unless it has clear multi-page responsibility.
- Suggested method names should match the page's domain (not `doThing()`).
</constraints>
<output_format>
Five sections:
1. **Locator review** — table: Current locator | Issue | Suggested
2. **Action method review** — table: Method | Granularity | Issue | Suggested
3. **Assertion method review** — table: Method | Issue | Suggested
4. **Constructor + class boundary** — bullets on issues
5. **Refactor diff** — diff-style changes
</output_format>
Before writing, count locators and methods; flag if > 25 / > 20 (likely needs split).Example
Common pitfalls
- Model proposes a 'cleanup' that loses functionality — verify methods aren't called by existing specs.
- Class split happens too aggressively (every page method becomes its own class). Force the 25-locator / 20-method threshold.
- Renaming methods breaks calling code — generate a deprecation map (`oldName -> newName`).
- Locator initialization moved to constructor but DOM isn't ready at construction time. Use Playwright's lazy locators (they don't query until used).
Tips
- Run after every 5-10 spec files are added; POMs drift toward bloat.
- Pair with `generate-playwright-pom` for the inverse problem (generating new POMs cleanly).
- Bundle multiple POM refactors into ONE PR for the codebase; cleaner history than per-POM PRs.
- When splitting a POM, validate that the new responsibilities each have own integration tests.
FAQ
POM is page-centric; Screenplay is actor-centric (\"Alice can sign in\" -> Alice.attemptsTo(SignIn.with(creds))). Screenplay is more verbose; pays off in suites with thousands of tests and very different user roles. POM is simpler; right for most projects.
Related prompts
Generate Playwright Page Object Model
Give the model a page description plus a list of UI elements and it returns a complete Page Object Model in TypeScript using Playwright's auto-waiting locators (getByRole / getByTestId), typed action and assertion methods, and a page-level fixture.
Open →Generate Cypress Page Object Model
Returns a Cypress Page Object class using cy.get() with data-cy preference, action methods that chain via `return this`, plus a commands.js file for cross-page utilities and a sample spec consuming the POM.
Open →Review Test Code for Anti-Patterns
Reads a test file and returns a categorized list of anti-patterns — hard sleeps, shared mutable state, weak assertions (`toBeTruthy` instead of `toEqual`), missing teardown, mixed setup/assertion concerns — each with line numbers, severity, and a suggested fix.
Open →Refactor Test Suite for DRY
Scans a set of test files and identifies duplicated setup, fixture state, and assertion patterns — proposes refactors using Playwright fixtures, factory functions, or shared helper modules with concrete code diffs. Warns against premature abstraction (single-use helpers).
Open →