Dinesh
Dinesh

Reputation: 1880

Cypress on uncaught exception is not working

I have the following sample script to experiment exception handling in Cypress. But the exception is not being caught. What am I missing here?

Cypress.on('uncaught:exception', (err, runnable) => {
    Cypress.log("this is top-level exception hadling")
    return false
})

context('Actions', () => {
    
    it('sample_testing', () => {
    
        cy.on('uncaught:exception', (err, runnable) => {
            cy.log("this is test-level exception hadling")
            return false
        })
        
        cy.get("#notfound", {timeout:1000})
    })
    
})

Please note that there is no element with id notfound in my web page.

Upvotes: 5

Views: 10015

Answers (2)

user15239601
user15239601

Reputation:

Uncaught exceptions are only for application errors. Failures within the test code are caught by Cypress but are then reported as a test fail.

Test Fails

To prevent that, you can use the fail event

Cypress.on('fail', (error, runnable) => {
  debugger

  // we now have access to the err instance
  // and the mocha runnable this failed on

  throw error // throw error to have test still fail
})

it('calls the "fail" callback when this test fails', () => {
  // when this cy.get() fails the callback
  // is invoked with the error
  cy.get('element-that-does-not-exist')
})

Uncaught exceptions

Take a look at the recipe Handling Application Errors

app.js - throws an error

document.getElementById('error').addEventListener('click', () => {
  console.log('application will throw an error in 1 second')
  setTimeout(() => {
    console.log('application is about to throw an error')
    throw new Error('Things went bad')
  }, 1000)
})

test - catch the error and selectively ignore if it has a certain message

  it('can be ignored', () => {
    /**
     * By using "cy.on()" we can ignore an exception in the current test only.
     * If you want to register exception handler for all tests using "Cypress.on()"
     * @see https://on.cypress.io/catalog-of-events
     * @param {Error} e The exception we caught
     * @param {Mocha.Runnable} runnable is the current test or hook during which the error is caught
     */
    cy.on('uncaught:exception', (e, runnable) => {
      console.log('error', e)
      console.log('runnable', runnable)

      // we can simply return false to avoid failing the test on uncaught error
      // return false
      // but a better strategy is to make sure the error is expected
      if (e.message.includes('Things went bad')) {
        // we expected this error, so let's ignore it
        // and let the test continue
        return false
      }
      // on any other error message the test fails
    })

    cy.visit('index.html')
    cy.get('button#error').click()
    // the error happens after 1000ms
    // we can use hard-coded wait, see the other test
    // to learn how to avoid an unnecessary wait
    cy.wait(1500)
  })

Upvotes: 5

Rosen Mihaylov
Rosen Mihaylov

Reputation: 1425

I tried many options for such a solution and this one gave me a better way to debug uncaught exceptions. This one logs the exception in the browser console:

Cypress.on('uncaught:exception', (err, runnable) => {
    // returning false here prevents Cypress from
    // failing the test
    cy.log('Uncaught exception... continuing...')
    return false
})


Cypress.on('fail', (error, runnable) => {
    console.log(error)

    // we now have access to the err instance
    // and the mocha runnable this failed on

    throw error // throw error to have test still fail
})

Cypress.on('window:before:load', (win) => {
    Cypress.log({
        name: 'console.log',
        message: 'wrap on console.log',
    });

    // pass through cypress log so we can see log inside command execution order
    win.console.log = (...args) => {
        Cypress.log({
            name: 'console.log',
            message: args,
        });
    };
});

Cypress.on('log:added', (options) => {
    if (options.instrument === 'command') {
        // eslint-disable-next-line no-console
        console.log(
            `${(options.displayName || options.name || '').toUpperCase()} ${
                options.message
            }`,
        );
    }
});

Upvotes: 0

Related Questions