Q16 of 48 · Cypress

How do you debug a flaky test in Cypress?

CypressMidcypressdebuggingflaky-testsmid

Short answer

Short answer: Reproduce locally with `cypress run` (not `open`), then use `--browser chrome --headed` plus `.only` to isolate. Inspect the recorded video, the screenshot, and the command log. Common causes: missing waits, animations, race conditions, shared test data, network-dependent timing.

Detail

Flake means the same code passes and fails non-deterministically. Cypress flake usually has one of a small number of root causes:

  1. Hard-coded waits and animations. cy.wait(500) masks timing without fixing it. Replace with .should('be.visible') or cy.wait('@aliasedRequest').
  2. Order-dependent state. A test relies on data created by an earlier test. With testIsolation: true the cookies are cleared but the database isn't — explicit reset (cy.task('resetDb')) is the fix.
  3. Network race. The test asserts on the page before the API call returns. Alias the request with cy.intercept and cy.wait('@alias') before asserting.
  4. Animations and transitions. A .click() lands on a button mid-animation and misses. Disable animations in test (.disable-animations body class) or use .should('not.have.css', 'opacity', '0') first.
  5. Real-time data shifts. Anything driven by Date.now() or live data. Stub the clock with cy.clock() and the data with cy.intercept.

The debugging workflow:

  • Run with --browser chrome --headed headed locally — sometimes the bug only manifests headless.
  • Inspect the screenshot at failure (auto-saved to cypress/screenshots/).
  • Watch the video (Cypress 13 records by default in run mode).
  • Add .only to the failing test, run repeatedly. If it never reproduces, you're missing context.
  • Add cy.log('marker A') calls to localise the failure.
  • Use cy.pause() in interactive mode to step through.

If a test flakes only in CI, the cause is usually environment: slower network, smaller viewport, missing fonts, animation timing. Reproduce with the CI's exact docker image when possible.

// EXAMPLE

// ❌ Flaky — race between request and assertion
cy.visit('/cart');
cy.get('[data-test=total]').should('contain', '£');

// ✅ Wait for the API to settle first
cy.intercept('GET', '/api/cart').as('cartLoad');
cy.visit('/cart');
cy.wait('@cartLoad');
cy.get('[data-test=total]').should('contain', '£');

// ❌ Flaky — animation in flight
cy.get('[data-test=modal-open]').click();
cy.get('[data-test=modal]').click();

// ✅ Wait for animation to complete
cy.get('[data-test=modal-open]').click();
cy.get('[data-test=modal]')
  .should('have.css', 'opacity', '1')
  .click();

// WHAT INTERVIEWERS LOOK FOR

A systematic taxonomy of flake causes (timing, state, animation, network) plus the artefacts to inspect (video, screenshot, log).

// COMMON PITFALL

Adding `cy.wait(N)` to make the flake go away — that hides the symptom and the test will eventually break again at a different N.