Hero Background

Next-Gen App & Browser Testing Cloud

Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Next-Gen App & Browser Testing Cloud

How to maintain and update test cases in Cypress?

You maintain and update Cypress test cases by using resilient data-cy selectors, extracting repeated logic into custom commands, storing test data in fixtures, applying the Page Object Model for large suites, and refactoring specs whenever the application changes. Keeping tests isolated and running them continuously in CI catches regressions early and keeps the suite trustworthy as your app evolves.

Understanding Cypress Test Structure

Cypress is a JavaScript-based front-end testing tool built on Mocha and Chai. When you create a project, it generates a folder structure that organizes where tests, fixtures, and support files live. Good maintenance starts with respecting that structure: keep specs focused, keep reusable helpers in the support folder, and keep test data in fixtures. A well-organized project is far cheaper to update when the UI or requirements change.

Use Resilient Selectors

The single biggest cause of brittle Cypress tests is selectors tied to styling or markup. Cypress recommends dedicated test attributes such as data-cy or data-testid, which are decoupled from CSS and JavaScript changes. When a designer reworks classes, your tests keep passing because the test hook is untouched.

<button data-cy="submit-login">Log In</button>
// Prefer this
cy.get('[data-cy="submit-login"]').click();

// Over this brittle, style-coupled selector
cy.get('.btn.btn-primary.mt-3').click();

Extract Reusable Logic Into Custom Commands

Custom commands are the most effective maintenance lever in Cypress. Encapsulate repetitive flows like login once, and every spec reuses them. When the flow changes, you edit a single command instead of dozens of tests.

// cypress/support/commands.js
Cypress.Commands.add('login', (email, password) => {
  cy.get('[data-cy="email"]').type(email);
  cy.get('[data-cy="password"]').type(password);
  cy.get('[data-cy="submit-login"]').click();
});

Cypress.Commands.add('getBySel', (selector, ...args) => {
  return cy.get('[data-cy="' + selector + '"]', ...args);
});

// In a spec
cy.login('[email protected]', 'Secret123');
cy.getBySel('dashboard-title').should('be.visible');

Externalize Test Data With Fixtures

Hardcoded data scattered across specs is painful to update. Store it in fixture files and load it with cy.fixture(), or generate dynamic values with a faker file. This keeps specs readable and lets you change data in one place. You can also move shared routes into a routes.js file and import it wherever needed.

// cypress/fixtures/user.json -> { "email": "[email protected]", "password": "Secret123" }
cy.fixture('user').then((user) => {
  cy.login(user.email, user.password);
});

Apply the Page Object Model for Large Suites

For larger applications, the Page Object Model separates locators and page actions from test logic. When the UI changes, you update the page object rather than every spec that touches that screen. Cypress custom commands cover many cases, but page objects add structure once a suite grows. See also what are page objects in Cypress.

Keep Tests Isolated and Refactor Regularly

  • Isolation: Every test should be self-contained and not rely on state left by a previous test.
  • Descriptive names: Test names should state the action and expected outcome so intent is clear without reading code.
  • Refactor with the app: As features evolve, evolve the tests. Treat test code like production code and review it.
  • Version control hygiene: Use .gitignore to skip generated Cypress artifacts so only meaningful changes are committed.
  • Run in CI/CD: Wire Cypress into the pipeline so tests act as quality gates on every change. See integrating Cypress with CI tools.

Common Mistakes and Troubleshooting

  • Brittle selectors: Coupling to CSS classes breaks tests on redesigns. Switch to data-cy attributes.
  • Copy-pasted flows: Duplicated login or setup logic multiplies maintenance. Consolidate into custom commands.
  • Fixed waits: cy.wait(5000) hides timing bugs and slows suites. Assert on state and let Cypress retry.
  • Interdependent tests: Tests that share state fail unpredictably. Reset state in beforeEach and keep them independent.
  • Ignoring flakiness: A tolerated flaky test erodes trust. Diagnose the root cause instead of re-running. See debugging Cypress failures.

Maintaining Tests Across Browsers and Devices

A maintainable suite must also stay green everywhere your users run. Running Cypress only on a local Chrome hides browser-specific regressions that surface later. With TestMu AI, you can execute your existing Cypress specs across 3000+ real browsers and devices in parallel, so every update is validated cross-platform before merge. Pairing well-structured tests with a scalable automation testing cloud keeps maintenance low even as coverage grows. For deeper skills, explore exception handling in Cypress.

Conclusion

Maintaining Cypress tests is mostly about reducing coupling and duplication. Anchor selectors to dedicated test attributes, push repeated logic into custom commands, externalize data into fixtures, adopt page objects for large suites, keep tests isolated, and refactor as the app changes. Run everything continuously across real browsers, and your suite stays fast, reliable, and cheap to update.

Frequently Asked Questions

What selectors should I use for maintainable Cypress tests?

Use dedicated test attributes like data-cy or data-testid instead of CSS classes or generated IDs. These attributes exist only for testing, so they do not change when styling or markup is refactored, which keeps selectors stable and reduces test breakage.

How do custom commands help maintain Cypress tests?

Custom commands encapsulate repetitive actions such as login or form filling into a single reusable function. When the flow changes, you update the command in one place and every test that uses it inherits the fix, which greatly reduces maintenance effort.

Should I use the Page Object Model in Cypress?

The Page Object Model separates locators and page actions from test logic. When the UI changes you only edit the page object, not every spec. It is optional in Cypress, where custom commands cover many cases, but it helps for large suites.

How do I manage test data in Cypress?

Store test data in fixture files as JSON or JavaScript rather than hardcoding it in specs. Load it with cy.fixture() or generate dynamic data with a faker file. Externalized data makes tests readable and easy to update in one place.

How do I fix flaky Cypress tests?

Address root causes rather than adding fixed waits. Use resilient selectors, rely on Cypress built-in retry-ability with proper assertions, keep tests isolated, and avoid dependencies on prior test state. Review and refactor flaky specs regularly.

How often should Cypress tests be reviewed?

Treat test code like application code. Review and refactor it whenever features change, and audit the suite periodically to remove obsolete cases, fix flaky tests, and consolidate duplicated logic into custom commands or page objects.

Related Questions

Test Your Website on 3000+ Browsers

Get 100 minutes of automation test minutes FREE!!

Test Now...

KaneAI - Testing Assistant

World’s first AI-Native E2E testing agent.

...

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests