Debugging

Improve this doc

What You’ll Learn

  • How Cypress runs in the runloop with your code, keeping debugging simple and understandable for modern web developers
  • How Cypress embraces the standard DevTools
  • How and when to use debugger and the shorthand .debug() command

Using debugger

Your Cypress test code runs in the same run loop as your application. This means we have access to variables and the code running on the page, as well as the things the browser makes available to you, like document, window, and, of course, debugger.

Debug Just Like You Always Do… Almost

Based on those statements, you might be tempted to just throw a debugger into your test, like so:

it('let me debug like a fiend', function() {
  cy.visit('/my/page/path')

  cy.get('.selector-in-question')

  debugger // Doesn't work
})

…alas, this will not work. As you may remember from Introduction to Cypress, cy.* commands simply enqueue an action to be taken later. Can you see what this test will do given that perspective? cy.visit() and cy.get() will both return immediately, having enqueued their work to be done later, and debugger will be executed before anything has happened.

Let’s use .then() to tap into the Cypress command flow and execute debugger at the appropriate time:

it('let me debug like a fiend', function() {
  cy.visit('/my/page/path')

  cy.get('.selector-in-question')
    .then(($selectedElement) => {
      debugger // Works like you think!
    })
})

Now we’re in business! The first time through, cy.visit() and the cy.get() chain (with its .then() attached) are enqueued for Cypress to execute. The it block exits, and Cypress starts its work:

  1. The page is visited, and Cypress waits for it to load.
  2. The element is selected, and Cypress automatically waits and retries for a few moments if it isn’t found immediately.
  3. The function passed to .then() is executed, with the found element yielded to it.
  4. Within the context of this function, debugger is called, halting the browser and focusing on the DevTools.
  5. You’re in! Inspect the state of your application like you normally would if you’d dropped the debugger into your application code.

Using .debug()

But that’s a lot of typing just to call debugger in context, yeah? Cypress exposes a shortcut for this, .debug(). Let’s rewrite the test using this helper method:

it("let's me debug like a fiend", function() {
  cy.visit('/my/page/path')

  cy.get('.selector-in-question')
    .debug()
})

Ah, that’s better! And functionally equivalent. The current subject that was yielded by the cy.get() is exposed as subject so that you can interact with it in the console.

This is just another example of how Cypress seeks elegance and expressivity for the modern web tester. Fewer keystrokes, more power, don’t break standard assumptions, and we all win.

Use .debug() to quickly inspect any (or many!) part(s) of your application during the test. You can attach it to any Cypress chain of commands to have a look at the system state at that moment.

Using the DevTools

Though Cypress has built out an excellent Test Runner to help you understand what is happening in your app and your tests, there’s simply no replacing all the amazing work browser teams have done on their built-in development tools. Once again, we see that Cypress goes with the flow of the modern ecosystem, opting to leverage these tools wherever possible.

See it in action!

You can see a walk-through of debugging some application code from Cypress in this segment from our React tutorial series.

Debug the Command Line

Cypress is built using the debug module. That means you can receive helpful debugging output by running Cypress with this turned on.

On Mac or Linux:

DEBUG=cypress:* cypress open

On Windows:

set DEBUG=cypress:*

Read more about the CLI options here.

Debug the Browser Driver

When Cypress is running in your browser, you can have every event it fires logged out to the console.

Read more about logging events in the browser here.