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:
- Hard-coded waits and animations.
cy.wait(500)masks timing without fixing it. Replace with.should('be.visible')orcy.wait('@aliasedRequest'). - Order-dependent state. A test relies on data created by an earlier test. With
testIsolation: truethe cookies are cleared but the database isn't — explicit reset (cy.task('resetDb')) is the fix. - Network race. The test asserts on the page before the API call returns. Alias the request with
cy.interceptandcy.wait('@alias')before asserting. - Animations and transitions. A
.click()lands on a button mid-animation and misses. Disable animations in test (.disable-animationsbody class) or use.should('not.have.css', 'opacity', '0')first. - Real-time data shifts. Anything driven by
Date.now()or live data. Stub the clock withcy.clock()and the data withcy.intercept.
The debugging workflow:
- Run with
--browser chrome --headedheaded 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
.onlyto 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.