Skip to content

Review a Page Object Model for Refactoring

Updated 2026-06-08·advanced·Test Code Review

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