Q13 of 48 · Cypress

How do you select elements in Cypress and what's the recommended selector strategy?

CypressJuniorcypressselectorsfundamentals

Short answer

Short answer: Use `cy.get(selector)` for CSS, `cy.contains(text)` for text, `cy.find()` to scope inside another element. Cypress recommends `data-test`, `data-cy`, or `data-testid` attributes — they're stable under refactor. Avoid CSS class names and XPath; both are coupled to implementation.

Detail

cy.get accepts any CSS selector. The framework also exposes cy.contains (find by visible text) and chained .find / .parent / .children for DOM traversal.

The selector hierarchy Cypress recommends, from best to worst:

  1. data-test / data-cy / data-testid — explicit testing attributes the team controls. Stable across CSS rewrites and class renames. cy.get('[data-test=submit]').
  2. role / aria-label — accessible names. Tests double as accessibility audits. cy.get('button[aria-label="Submit"]') — though Cypress lacks a built-in getByRole (Playwright/Testing Library do).
  3. Text contentcy.contains('Submit'). Brittle if copy changes; use sparingly.
  4. CSS classes / IDs / nested selectorscy.get('.btn-primary > span'). Couples tests to implementation. Avoid.
  5. XPath — requires a plugin and almost never the right answer in a Cypress project.

The team agreement is "every interactive element gets a data-test attribute." It's a small dev-time cost for a big test-stability win.

cy.contains is convenient but matches anywhere in the DOM by default. Scope it: cy.contains('[data-test=cart]', 'Apples') looks for "Apples" inside the cart only.

// EXAMPLE

selectors.cy.ts

// ✅ Recommended — stable testing attribute
cy.get('[data-test=submit-order]').click();

// ✅ Acceptable — accessible name
cy.get('button[aria-label="Submit order"]').click();

// ⚠️  Use sparingly — copy changes break the test
cy.contains('Submit order').click();

// ⚠️  Scope cy.contains to avoid matching elsewhere
cy.contains('[data-test=cart-row]', 'Apples').should('be.visible');

// ❌ Avoid — coupled to CSS implementation
cy.get('.btn.btn-primary > span.icon').click();

// Chained DOM traversal
cy.get('[data-test=cart]')
  .find('[data-test=cart-row]')
  .should('have.length', 3);

// WHAT INTERVIEWERS LOOK FOR

Naming the recommended hierarchy and the architectural commitment (every interactive element gets a test attribute). Bonus for scoping `cy.contains` to avoid global matches.

// COMMON PITFALL

Writing tests against CSS classes and being surprised when a designer's class rename breaks 50 tests.