Skip to content

Generate a Cypress Page Object Model with AI

Updated 2026-06-08·intermediate·Test Automation

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.

When to use it

  • Starting a new Cypress suite and need a consistent POM scaffold.
  • Migrating selectors from CSS/XPath to data-cy testid convention.
  • Comparing Cypress vs Playwright POM patterns for an architecture decision.
  • Standardizing custom commands across multiple page objects.

The prompt

XML-tagged — best for Claude 4.x

<role>
You are a senior Cypress automation engineer with deep experience in the Cypress chained command model and custom command registration. You enforce data-cy testid convention and reject CSS selectors except as last resort.
</role>

<context>
The team uses Cypress 14+ with JavaScript (TypeScript optional). POMs are classes with action methods that return `this` (for chaining) and use `cy.get('[data-cy=...]')` as the primary locator strategy. Cross-page utilities live in `cypress/support/commands.js` and are registered with `Cypress.Commands.add`.
</context>

<task>
Generate a complete Cypress Page Object Model for the page below, including:
1. A class with action methods that chain via `return this`
2. `cy.get('[data-cy=...]')` selectors (CSS only as last resort)
3. Assertion methods using `.should('be.visible')` and similar
4. A `visit()` method
5. A separate `commands.js` snippet registering 1-2 reusable custom commands the page object would benefit from
6. A sample spec file showing the POM in use
</task>

<input>
Page name: {page_name}
Page URL path: {url_path}
Elements (label → data-cy testid):
{element_list}

User intents on this page:
{intents}
</input>

<constraints>
- Cypress 14+ syntax.
- Primary locator: `cy.get('[data-cy=<id>]')`. CSS only when data-cy is impossible.
- Action methods return `this` for chaining.
- No `cy.wait(<ms>)` hard waits.
- Custom commands MUST be in a separate `commands.js` snippet, not inline in the POM.
</constraints>

<output_format>
Three code blocks:
1. The POM class (e.g., `cypress/support/pages/LoginPage.js`)
2. Custom commands (`cypress/support/commands.js` snippet)
3. Sample spec consuming the POM
Followed by 3-5 "Next steps" bullets (e.g., add data-cy attrs to the app, wire commands.js, etc.).
</output_format>

Think through which actions naturally chain vs which need separate calls before writing.

Example

Common pitfalls

  • Model produces Playwright-style async/await disguised as Cypress — Cypress commands are not awaited. Re-prompt with explicit Cypress version mention.
  • Custom commands sometimes leak into the POM class body — enforce separate commands.js in constraints.
  • Without data-cy emphasis, model defaults to class/text selectors, brittle to CSS changes.
  • Action methods may forget `return this`, breaking chaining for downstream callers.

Tips

  • Add `cy.session()` patterns in commands.js for any login flow — massive speedup for suites with auth.
  • Pair this POM pattern with `should('not.exist')` for negative assertions; Cypress retries it correctly.
  • If your app doesn't have data-cy attrs yet, generate the POM first, then add the attrs to the app one by one as you implement.
  • Use Cypress Cloud parallel runs — the POM structure doesn't need changes; only spec sharding does.

FAQ

Playwright has overtaken Cypress for new projects due to faster execution, multi-tab support, and better mobile emulation. Cypress remains strong for existing teams already invested. Both can produce great test suites — the framework is rarely the bottleneck.

Related prompts

Use with these tools