100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Testing

Debugging Cypress Tests

Learn the practical toolkit for debugging failing or flaky Cypress tests — from time-travel debugging and the Command Log to browser DevTools and cy.debug().

CI & ScalingBeginner8 min readJul 10, 2026
Analogies

Time-Travel Debugging with the Command Log

The Cypress Test Runner's Command Log lists every command executed during a test in order, and clicking any entry snapshots the application's DOM back to exactly that moment — this 'time travel' is possible because Cypress runs in the same browser process as the application under test, giving it direct access to the live DOM rather than communicating over a remote protocol like Selenium's WebDriver does. Hovering over a .type() or .click() command highlights the actual element that was acted on directly in the app preview pane, which is often enough on its own to spot a mistaken selector matching the wrong element before reading a single line of the failure message.

🏏

Cricket analogy: This is like a coach scrubbing through ball-by-ball video footage of an innings and pausing at any specific delivery to see the exact field placement at that moment, rather than only having access to the final scorecard.

`cy.debug()`, `.pause()`, and Browser DevTools

Inserting cy.debug() at any point in a test chain pauses execution and drops a debugger statement, opening browser DevTools (if already open) with the previous command's subject available in the console as $0-style access — this lets you run arbitrary jQuery-style queries against the exact DOM state at that point. .pause() is a coarser tool: it halts the entire test runner, letting you step forward command-by-command using the Test Runner's UI controls, which is useful for narrating exactly what's happening to a colleague or slowly walking through a suspected race condition. Because Cypress tests execute in the real browser, the standard DevTools Elements, Network, and Console panels all work normally alongside these tools — you can inspect actual network requests, not a mocked abstraction of them, unless you've explicitly stubbed a route with cy.intercept().

🏏

Cricket analogy: This is like a DRS review pausing live play entirely so umpires can walk through the exact sequence frame-by-frame with full replay controls, as opposed to just glancing at a single freeze-frame — .pause() gives that same full-control walkthrough.

javascript
cy.get('[data-cy="checkout-form"]').within(() => {
  cy.get('input[name="email"]').type('shopper@example.com');
  cy.get('input[name="promo"]').type('SAVE10');
  cy.debug(); // pause here, inspect DOM/state in DevTools console
  cy.get('button[type="submit"]').click();
});

cy.intercept('POST', '/api/checkout').as('checkout');
cy.wait('@checkout').its('response.statusCode').should('eq', 200);

Cypress automatically opens Chrome DevTools when running with cypress open --browser chrome, and the Command Log's console output for a selected command (like the exact elements .get() matched) is printed to the DevTools console — a habit worth building is checking the console panel, not just the Command Log sidebar, since it often shows more detail like the number of matched elements.

Debugging CI-Only Failures

A test that passes locally but fails only in CI is one of the hardest debugging scenarios, since you can't attach live DevTools to a headless CI run. The standard toolkit is: pull the recorded video and any failure screenshot from CI artifacts or Cypress Cloud first, since the screenshot often visually reveals the problem (a modal never opened, an unexpected error banner). If that's inconclusive, Cypress Cloud's DOM snapshots (available with --record) let you inspect the actual DOM state at each command from that specific CI run, not just a re-creation. When neither is enough, reproducing the CI environment locally — running cypress run --headless with the same viewport, browser, and resolution the CI job uses — often surfaces environment-specific issues like a smaller default viewport causing an element to be covered by a sticky header.

🏏

Cricket analogy: This is like a batter dismissed by a delivery that looked fine on live TV broadcast angles, requiring the Snicko and Hot Spot ultra-edge technology available only in a formal review to actually reveal the tiny edge that caused the dismissal.

Do not assume a CI-only failure is 'just flake' and add a retry without investigating — CI environments frequently expose real bugs that local development masks, such as timezone differences, smaller default viewports, or missing seed data that a developer's long-lived local database happens to have.

  • The Command Log's time-travel feature snapshots the real DOM at any executed command, since Cypress runs inside the same browser process as the app.
  • cy.debug() drops a debugger statement with the previous command's subject available in the console for ad-hoc inspection.
  • .pause() halts the whole runner for manual step-by-step walkthroughs, useful for narrating or diagnosing race conditions.
  • Standard DevTools panels (Elements, Network, Console) work normally alongside Cypress's own tooling.
  • CI-only failures require pulling the recorded video/screenshot and, ideally, Cypress Cloud DOM snapshots from that specific run.
  • Reproducing CI's exact browser, viewport, and headless settings locally often surfaces environment-specific bugs.
  • CI-only failures are frequently real bugs (viewport, timezone, seed data), not just flake — investigate before adding a retry.

Practice what you learned

Was this page helpful?

Topics covered

#Testing#CypressStudyNotes#TestingQA#DebuggingCypressTests#Debugging#Cypress#Tests#Time#StudyNotes#SkillVeris