Debugging a failing or confusing test efficiently is its own skill. This lesson covers the core debugging tools Cypress provides and how to combine them with browser DevTools.
Core Debugging Tools
cy.pause() halts test execution at that exact point, letting you inspect the app manually and step through remaining commands one at a time. cy.debug() logs the current subject to the browser console and triggers a debugger breakpoint, useful when working directly in DevTools.
cy.get('[data-cy="cart-total"]').debug(); // logs subject, pauses at a breakpoint
cy.pause(); // halts here; click "Next" in the Test Runner to continue
Both commands are meant for temporary use during development, not for committing into a finished test.
cy.pause() can be placed anywhere in a chain to halt execution at that point.
cy.debug() logs the current subject and triggers a breakpoint if DevTools are open.
cy.log() writes a custom message directly into the command log for context.
A plain debugger; statement works inside .then() callbacks like normal JavaScript.
Debugging Tools Cheat Sheet
Choosing the right debugging tool for a given situation.
Goal
Tool
Pause and manually inspect the app
cy.pause()
Log the current subject and set a breakpoint
cy.debug()
Add a custom note to the command log
cy.log('message')
Step through custom .then() logic
debugger; inside the callback
Inspect DOM snapshot at any command
Click that command in the Test Runner
Combining cy.pause() with Browser DevTools
With the Test Runner's browser DevTools open (they work exactly like normal Chrome/Firefox DevTools), cy.pause() gives you a frozen moment to inspect the real DOM, check computed styles, or run manual JavaScript in the console, all against the actual state your test reached.
Open DevTools before pausing, so you don't miss the frozen state.
Use the Elements panel to inspect exact computed styles and attributes.
Use the Console panel to run ad hoc JavaScript against the live page.
Debugging Custom Logic Inside .then()
Custom .then() callbacks run as plain JavaScript, so a standard debugger; statement works exactly as it would anywhere else, pausing execution when DevTools are open and letting you step through with normal browser debugging controls.
cy.get('[data-cy="cart-items"]').then(($items) => {
const total = [...$items].reduce((sum, el) => sum + Number(el.dataset.price), 0);
debugger; // inspect total and $items here
expect(total).to.be.greaterThan(0);
});
Common Mistakes
Leaving cy.pause() or cy.debug() calls committed in finished test code, unintentionally freezing CI runs.
Debugging exclusively by reading terminal output from headless runs instead of using the interactive Test Runner.
Not opening DevTools before pausing, missing the chance to inspect the frozen state.
Overusing cy.log() everywhere instead of relying on the command log's built-in step-by-step visibility.
Key Takeaways
cy.pause() halts execution for manual inspection; cy.debug() logs the subject and sets a breakpoint.
Browser DevTools work normally inside the Test Runner and pair well with cy.pause().
Plain debugger; statements work inside .then() callbacks like any other JavaScript.
Debugging tools are for development use only and should not remain in committed test code.
Pro Tip
Before reaching for cy.pause(), try clicking through the command log in the interactive Test Runner first, the DOM snapshots it already captured often answer the question immediately, without needing to halt and manually re-inspect anything.
You now have practical debugging techniques. Next, learn how Screenshots capture visual state for later review.