Reputation: 1880
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
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.
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')
})
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
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