Exception Handling In Cypress and How to Handle Them

  • Learning Hub
  • Exception Handling In Cypress and How to Handle Them

OVERVIEW

Cypress is a powerful tool for automating web application testing, but sometimes exceptions can disrupt the flow of your tests. Exceptions can prevent your test suite from completing successfully, which makes it challenging to identify the root cause of the issue.

That’s why proper exception handling is crucial for the smooth operation of your tests and ensuring their results' accuracy.

Exception handling in Cypress can be beneficial for identifying and addressing errors that occur during test execution. By handling exceptions, you can validate your commands' output, ensure that your tests run smoothly, and produce accurate results. This can help you to write more reliable and robust tests and to handle errors that may arise during test execution gracefully.

If you encounter an assertion error or uncaught exception while running a test case in Cypress and you have not properly handled the exception, the test will fail, and it may be challenging to determine the root cause of the issue.

However, if you have properly handled the exception, the error will be logged, and you can refer to the error message to handle and resolve the issue.

In this tutorial post, you will learn the concept of exception handling in Cypress in detail and ensure that the tests run smoothly.

What is Exception Handling?

Exception handling is a process in which a program handles runtime errors that occur during the execution of the program. Exceptions are typically thrown when something unexpected or unusual happens during the execution of a program, such as an exception on the webpage or an exception in the code.

An exception could result in your test abruptly failing and providing unclear error messages. It could also lead to a lack of insight into what went wrong during the test execution.

Ignoring or failing to handle exceptions can lead to unreliable test results and hinder your team's productivity. However, if you handle the exceptions proactively and effectively, it will ensure that your Cypress e2e tests run smoothly and provide accurate results.

There are various ways to handle exceptions in Cypress test automation, such as using the 'fail' and 'uncaught:exception' events and adding options like 'failOnStatusCode: false' to certain commands.

By implementing exception handling in Cypress tests, you can improve the reliability and robustness of your test suite.

...

Why is Exception Handling important?

Exception handling allows the program to recover from exceptions and continue running rather than crashing or terminating unexpectedly.

​​This is especially important in test automation, where you want to identify and isolate problems in your code or application as quickly as possible.

In addition, exception handling can help prevent your tests from failing due to errors that are outside your control, such as network or server issues. By handling these errors and continuing to execute your tests, you can ensure that your test suite is as robust as possible.

Let’s try to understand: For example, running a test in Cypress will encounter an assertion error on the page because the element is unavailable. In this case, the test case fails, and the test execution is stopped.

But if we handle the exception in code and rerun the same test case, the test case won’t fail this time, even if the assertion error is there.

You can also log a custom message in the logs so that it will be understandable by the whole team. This allows you to gracefully handle errors and continue with the test execution rather than having the test fail.

Exception Handling in Cypress

In the context of Cypress automation, exceptions can occur for various reasons. Below are the most common types of exceptions in Cypress:

  • Exception due to unexpected status code
  • Exception due to the failure of the test
  • Exception due to an uncaught exception in the application

To handle the above exceptions, you can use cy.on or Cypress.on commands, which allow listening to all events, including the error ones in your application. However, these event listeners have different scopes and behave differently.

The cy.on method registers an event listener within a specific test. It is bound to the individual test and will be removed once it ends. If you place cy.on the outside of a test, it will be ignored.

On the other hand, the Cypress.on method is used to register a global event listener that applies to all tests. It is not bound to any specific test and will not be unbound unless you manually unbind it.

Therefore, if you want to register an event listener that applies to all tests, you should use the Cypress.on method. However, if you only want to register an event listener for a specific test, you should use the cy.on method.

You can also Subscribe to the LambdaTest YouTube Channel and stay updated with the latest tutorials around automated browser testing, Selenium testing, Cypress E2E testing, CI/CD, and more.

Let’s cover all three scenarios in detail in the next section of this Cypress tutorial on exception handling in Cypress.

How to Handle Exceptions in Cypress due to Unexpected Status Codes?

By default, Cypress throws an exception if the server responds with a status code other than 2xx and 3xx. This can be useful for ensuring that the tests fail if the application being tested returns an error status code, such as a 400 (Bad Request) or a 500 (Internal Server Error). To learn more about it, you can go through this tutorial on getting response status code using HTTP Apache client.

If you encounter a test scenario in Cypress UI automation where you expect a status code other than 2xx or 3xx, you can add the option failOnStatusCode: false in the test code. This is to inform Cypress to continue with test execution instead of failing immediately.

html status code

Let’s try understanding exception handling in Cypress with an example: Open a URL that returns a status code 404.

Test Scenario:

Open URL: https://ecommerce-playground.lambdatest.io/index.php?route=account/login/1 using cy.visit().

Implementation:


describe("Cypress Exception Handling", () => {
 it("Fail on status code", () => {
cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login/1" );
 });
})

GitHub

When you run the above test case, you would see the result just like shown below:

Exception Handling In Cypress Status Codes test case

The above test case is failing because Cypress throws an error if it detects the status code is other than 2xx and 3xx.

To avoid the test case from failing due to the status codes, you can use the failOnStatusCode:false option when opening a URL/requesting with the request command.

Let’s modify the last test case to include failOnStatusCode:false so that the test passes even if the response status code is other than 2xx and 3xx.




describe("Cypress Exception Handling", () => {
 it("Fail on status code", () => {
cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login/1", { failOnStatusCode: false } ) 
}) 
})

Execution:.

Run npx cypress open on the terminal.

As shown in the screenshot below, the test case has not failed this time but has passed.

Exception Handling In Cypress Status npx cypress open

By using the { failOnStatusCode: false } option in cy.visit, you can just modify the test case not to fail when the application returns a status code other than 2xx and 3xx.

You can handle unexpected status codes when calling any API as well. Below is the sample test case to pass failOnStatusCode:false in the API test.




describe("Cypress Exception Handling", () => {
 it("Fail on status code by calling api", () => {
cy.request(
{url:"https://ecommerce-playground.lambdatest.io/index.php?route=account/login/1",
     failOnStatusCode: false, })  
})  })
pass failOnStatusCode:false in the API test

To prevent API from failing on bad status code, you must pass option object failOnStatusCode:false to cy.request().

How to Handle Exceptions in Cypress due to Test Failures?

In Cypress UI testing, if a command fails, the test fails. To prevent a test case from failing due to a Cypress error, you can register a listener and ignore the error for the failing test.

Example

Test a login form by entering the incorrect password and then verify the error message (for wrong credentials).

If the element (error-message, which you are trying to search) is not present in the HTML, then it would throw an exception in the Cypress Test Runner stating that “Timed out retrying after 4000ms: Expected to find element: .error-message, but never found it.”

Test Scenario:

Implementation:


describe("Display Error on wrong credentials", () => {
 it("displays an error message when the password is incorrect", () => {  cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login"
   )
   cy.get('[id="input-email"]').type("lambdatest.Cypress@disposable.com")
   cy.get('[id="input-password"]').type("Cypress1234!!")
   cy.get('[value="Login"]').click()
   cy.get(".error-message").should("be.visible")
 })  
})

Execution:

Run npx cypress open on the terminal. It throws an error on the page, as shown below:

Run npx cypress openerror on the page

In the above case, the test is failing because it is trying to access an element that does not exist. In Cypress, a ‘fail’ event is emitted when any test fails.

You can handle test failure exceptions in 2 ways.

  • Fix it for individual spec files by adding the exception handling code in each spec file.
  • Fix all the spec files at once by adding the exception handling code in support e2e.js (Cypress version 10 and above) because it is loaded before any test/spec file is evaluated. If you are using an older version of Cypress and wish to migrate to Cypress 10, you can follow this tutorial on Cypress 10 migration.

Add the exception handling code in each spec file.

To fix the issue, you can debug the application code or update your test case by adding the below code to handle errors.


cy.on("fail", (err, runnable) => {
     console.log(err.message);
     return false;
   });

Code Walkthrough:

The code above uses the cy.on command to register a callback function that will be executed whenever a test fails. The callback function takes two arguments: err and runnable.

  • err returns information about the error that occurred. It has a message property that can be accessed to get the error message.
  • runnable represents the test that failed. It has properties such as title, fullTitle, and parent.

Inside the callback function, the error message is logged to the console using console.log(err.message). The function returns false, telling Cypress not to log the error to the command log or the test results.

This is useful if you want to handle the error in a specific way and do not want Cypress to log the error as part of the test results.

Implementation:


describe("Display Error on wrong credentials", () => {
 it("Test Failure when trying to find incorrect locator- error Message", () => {
   cy.on("fail", (err, runnable) => {
     cy.log(err.message);
     return false;
   });
   cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login");
   cy.get("input[name=email]").type("test@example.com");
   cy.get("input[name=password]").type("incorrectpassword");
   cy.get('[value="Login"]').click();
   cy.get(".error-message").should("be.visible");
 });


});

In the test case, the exception is handled by using the command "cy.on('fail')" and then opening the URL with "cy.visit()", inputting values into the text box, and verifying the result.

Run the above test case, and you will observe that it will not fail, and the failed assertion will be ignored, as shown in the screenshot below.

URL with cy.visit

If you want to ignore the current test case failing, you can use cy.on(‘fail’) in it block. However, if you want to handle it for all the tests in one spec file, then you need to add Cypress.on(‘fail’) at the top of an individual spec file before it block.

Implementation:


Cypress.on("fail", (err, runnable) => {
    cy.log(err.message);
    return false;
  });

Code Walkthrough:

The Cypress .on('fail') function is used to specify a function that should be called whenever a test fails. The function takes two arguments: err, which is the error object that caused the test to fail, and runnable, which is an object representing the test that failed.

In this case, the function logs the error message to the console and returns false to indicate that the test has failed.

Implementation (2 tests in the spec file):


describe("Cypress Exception Handling", () => {
  Cypress.on("fail", (err, runnable) => {
    cy.log(err.message);
    return false;
  });
 it("Test Failure when trying to find incorrect locator- error Message", () =>
 { cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login")
  cy.get('[id="input-email"]').type("lambdatest.Cypress@disposable.com")
  cy.get('[id="input-password"]').type("Cypress1234!!")
  cy.get('[value="Login"]').click()
  cy.get(".error-message").should("be.visible")
}) 


it("Test Failure when trying to find incorrect locator - Password", () =>
{cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login")
cy.get('[id="input-email"]').type("lambdatest.Cypress@disposable.com")
cy.get('[id="input-password1"]').type("Cypress1234!!")
}) 
})

If you run the above test case, you can see the test case will not fail, but it will still show the error message.

Cypress onfail functionfunction logs the error message

Add the exception handling code globally for all test/spec files.

In the last section of this tutorial on exception handling in Cypress, we will learn how to handle the fail exception for a single spec file but what if you want to handle it for all the test/spec files.

In that case, you need to add the code in support/e2e.js (Cypress version 10 and above) since it is loaded before any test files are evaluated.

exception handling code globally

Here is an example of a test case without using cy.on(‘fail’)/Cypress.on(‘fail’) in the spec file but with Cypress.on(“fail’) in support/e2e.js.


describe("Cypress Exception Handling", () => {


it("Test Failure when trying to find incorrect locator- error Message
", () =>
{
cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login" )
cy.get('[id="input-email"]').type("lambdatest.Cypress@disposable.com")
 cy.get('[id="input-password"]').type("Cypress1234!!")
 cy.get('[value="Login"]').click()
 cy.get(".error-message").should("be.visible")
}) 


it("Test Failure when trying to find incorrect locator - Password
", () =>
{cy.visit("https://ecommerce-playground.lambdatest.io/index.php?route=account/login" )
cy.get('[id="input-email"]').type("lambdatest.Cypress@disposable.com")
 cy.get('[id="input-password1"]').type("Cypress1234!!") 
}) 
})

Now, if you execute the above test case, the result will still be the same as shown below:

returning customers page

The above example explains how to handle errors if my test case fails due to any Cypress error.

But there are scenarios where you want the test case to avoid failure only for one specific error but want it to fail for the other failures.

In this tutorial on exception handling in Cypress, you will learn to define the expected error message so that the test case would only ignore failure for the defined error message but will fail for the rest of the errors.

It can be done by adding the below sample code in support/e2e.js (Cypress version 10 and above):


Cypress.on("fail", (e, runnable) => {
console.log("error", e);
console.log("runnable", runnable);
console.log("message", e.message);
if ( e.name === "AssertionError" &&
!e.message.includes("Timed out retrying after 4000ms: Expected to find element: '.error-message', but never found it.")) 
{
throw e;
} })

In the above code, there is a condition added where it is checking that if an exception is Assertion Error and if the error message is not matching Timed out retrying after 4000ms: Expected to find element: `.error-message`, but never found it., it would throw an exception.

Let’s understand the scenario. Continuing with the last test case, where there are two tests.

  • One of them throws the error “Timed out retrying after 4000ms: Expected to find element: .error-message, but never found it.”
  • But the second test case throws a different error “Timed out retrying after 4000ms: Expected to find element: [id="input-password1"], but never found it.”

So, the second test case would fail in this case because we have handled exceptions only for one specific error. If the code detects any other exception on the page with a different error message, it will fail immediately.

Let’s run the test case and see the results:

new customer register accounty

So, in the above screenshot, it is visible that the 1st case is getting passed, whereas the second case failed because of the customized error message in Cypress.on(‘fail’), which was defined for only one error.

This exception is useful for debugging purposes and when you want to prevent the test from failing. However, it is strongly discouraged as the test should never fail in real time.

...

How to Handle Uncaught Exceptions in Cypress?

Uncaught exceptions in Cypress can occur when the application code throws an exception that is missed and handled within the test code. This can happen for various reasons, such as:

  • A bug in the application code that causes an exception to be thrown.
  • Unexpected changes to the application under test that cause the test code to fail.

If left unhandled, an uncaught exception can cause tests to fail unexpectedly, leading to unclear error messages and a lack of understanding of the root cause of the failure.

When an uncaught exception occurs, the program may stop executing and produce an error message or stack trace indicating where the exception occurred.

To avoid uncaught exceptions in Cypress, it is important to ensure that your test code is correct and it is appropriately handling any exceptions that may be thrown by the application.

Let’s try understanding handling uncaught exceptions in Cypress with a real-time scenario. Open index.html and click on the button, which is expected to throw an uncaught exception on the page.

Test Scenario:

  • Open URL: index.html using cy.visit().
  • Click on the button using cy.get().click().
  • Wait for 1000 milliseconds.

Implementation:


describe("Cypress Exception Handling", () => {
it("Uncaught Exception - Due to application error", () => {
cy.visit("index.html")
cy.get("button#error").click()
cy.wait(1000);    })   })

When you run the above test case, it fails because the page throws an uncaught exception.

uncaught exception in cypress

To avoid your test case from failing due to uncaught exceptions in Cypress, you can use cy.on/Cypress.on command to listen for the uncaught:exception event.

TThis event is emitted whenever an uncaught exception occurs within the Cypress command chain.

Add the exception handling code in each spec file.

To fix the issue, you can debug the application code or update your test case by adding the code below to handle errors.

Below is the sample code to handle an uncaught exception for a single test:


cy.on("uncaught:exception", (e, runnable) => {
console.log("error", e);
console.log("runnable", runnable);
console.log("error", e.message);
return false;
});

Code Walkthrough:

cy.on('uncaught:exception') is an event in Cypress that is triggered whenever an uncaught exception occurs in the application code. It allows you to handle the exception in a specific way, such as logging the error message or taking a screenshot.

The code above uses the cy.on command to register a callback function that will be executed whenever a test fails. The callback function takes two arguments: e and runnable.

  • e returns information about the error that occurred. It has a message property that can be accessed to get the error message.
  • runnable represents the test that failed. It has properties such as title, fullTitle, and parent.

The callback function logs the error message to the console using console.log(e.message). The function also returns false, telling Cypress not to log the error to the command log or the test results.

This is useful if you want to handle the error in a specific way and do not want Cypress to log the error as part of the test results.

Implementation:




describe("Cypress Exception Handling", () => {


it.("Uncaught Exception - Due to application error", () => {
cy.on("uncaught:exception", (e, runnable) => {
console.log("error", e);
console.log("runnable", runnable);
return false;
});


cy.visit("index.html");
cy.get("button#error").click();
cy.wait(1000);
});
});

Running the above test case will pass the test case this time because the exception was handled.

handling application errors cypresscypress exception handling page

In the above example, you learned how to handle errors if the test case failed due to any application error. However, there can be scenarios where you would want the test case to avoid failure only for one specific error but want it to fail for the other failures.

In this case, you should define the expected error message so that your test case would only ignore failure for the defined error message but will fail for the rest of the errors.

It can be done by adding the if condition in the uncaught exception code.

Implementation:


describe("Cypress Exception Handling", () => {


it("Uncaught Exception - Due to application error", () => {
cy.on("uncaught:exception", (e, runnable) => {
console.log("error", e);
console.log("runnable", runnable);
if (e.message.includes("Things went bad")) {
return false;
}
});
cy.visit("index.html");
cy.get("button#error").click();
cy.wait(1000);
});
});

Now, if my application throws any error other than Things went bad, the test case will fail because we handled the uncaught exception only for one specific message.

if-application-throws-any-error

Let’s see the negative scenario where we need to handle exceptions occurring due to when the message is Service Downtime.


describe("Cypress Exception Handling", () => {


it("Uncaught Exception - Due to application error", () => {
cy.on("uncaught:exception", (e, runnable) => {
console.log("error", e);
console.log("runnable", runnable);
if (e.message.includes("“Service Downtime”")) {
return false;
}
});


cy.visit("index.html");
cy.get("button#error").click();
cy.wait(1000);
});
});

In this case, the test case would fail as the exception is not handled in the code.

exception-not-handled-in-code

Adding a customized message helps to execute tests for the known exceptions, but If there is any other error, your test case should fail.

Add the exception handling code globally for all test/spec files.

In the last section of this tutorial on exception handling in Cypress, you learned how to handle the uncaught exception for a single spec file but what if you want to handle it for all the test/spec files?

In that case, you need to add the code in support/e2e.js (Cypress version 10 and above), since it is loaded before any test files are evaluated.


Cypress.on("uncaught:exception", (e, runnable) => {
console.log("error", e);
console.log("runnable", runnable);
if (e.message.includes("Things went bad")) {
return false;
}
});

Code Walkthrough:

In the above code, we are using Cypress.on(“uncaught:exception”). This Cypress event handler listens for uncaught exceptions that occur during the execution of the tests.

The event handler is passed two arguments: an error object e and the runnable that caused the exception.

  • e returns information about the error that occurred. It has a message property that can be accessed to get the error message.
  • runnable represents the test that failed. It has properties such as title, fullTitle, and parent.

The event handler logs the error, runs it to the console, then checks the error message to see if it includes the string Things went bad.

If it does, the event handler returns false, which prevents the exception from being thrown. If the error message does not include Things went bad, the exception is allowed to be thrown, and the test will fail.

This allows you to customize how exceptions are handled in the tests and provide more specific error messages to help you debug any issues that may arise.

Below is the screenshot of the support/e2e.js.

screenshot-of-the-supporte2e

Now, re-run the test case, and you will observe the test execution will not fail.

re-run-the-test-case

Until now, we have run Cypress tests locally. However, the true potential of Cypress testing can only be leveraged when used with cloud-based testing platforms like LambdaTest.

LambdaTest is a cross browser testing cloud that lets developers use Cypress for their integration testing. It provides a Cypress cloud grid of 50+ browser versions on which developers can run their Cypress tests in parallel.

LambdaTest

The Cypress 101 certification is designed for individuals who have a basic understanding of Cypress and want to enhance their end-to-end testing abilities. It is ideal for developers and testers who wish to advance their Cypress skills.

Conclusion

In conclusion, exception handling is essential to testing with Cypress. It allows you to handle and gracefully recover from errors that may occur during the execution of your tests. By proactively handling exceptions, you can ensure that your tests run smoothly and provide accurate results.

Exception handling in Cypress can be extremely useful for identifying and addressing errors during test execution. By handling exceptions, you can validate the output of your commands' output, ensure that your tests are running smoothly, and produce accurate results. This can help you to write more reliable and robust tests and to handle errors that may arise during test execution gracefully.

Frequently Asked Questions (FAQs)

How do you avoid uncaught exceptions in Cypress?

Uncaught exceptions in Cypress can be avoided by using the cy.on command to listen for the failed event and then using the .then command to handle the exception. For example, you can use cy.on('fail', (error) => { // handle the error here }) to catch the exception and handle it in a specific way. Additionally, you can also use Cypress.config('bail', true) in your configuration file to automatically stop the test run when an exception is encountered.

How to solve timeout error in Cypress?

There are a few ways to solve a timeout error in Cypress - Increase the default timeout, increase the timeout for a specific command, use cy.wait(): cy.wait(), use Retry-ability

What is before and beforeEach in Cypress?

before and beforeEach are Cypress commands that allow you to run a function before your tests run - before: It runs once before all of your tests. It is a good place to set up a common state that you want to persist across all your tests, such as logging in to an application or configuring a test environment. -beforeEach: It runs before each test. It is a good place to set up test-specific states, such as configuring test data or resetting the application's state between tests.

Author's Profile

...

Anshita Bhasin

Anshita Bhasin is a Senior QA Automation Engineer with over 9 years of experience in the software industry. Throughout her career, She has gained expertise in a variety of tools and technologies, including Rest Assured, Selenium, and Cypress. Currently, She is working at a PropTech company in Dubai. In addition to her technical expertise, she is also passionate about sharing her insights and experiences with others in the form of tutorials and workshops to help guide those just starting out in their careers or seeking advice on their professional paths. You can also follow her on Twitter.

Hubs: 04

  • Twitter
  • Linkedin

Reviewer's Profile

...

Himanshu Sheth

Himanshu Sheth is a seasoned technologist and blogger with more than 15+ years of diverse working experience. He currently works as the 'Lead Developer Evangelist' and 'Senior Manager [Technical Content Marketing]' at LambdaTest. He is very active with the startup community in Bengaluru (and down South) and loves interacting with passionate founders on his personal blog (which he has been maintaining since last 15+ years).

  • Twitter
  • Linkedin

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Did you find this page helpful?

Helpful

NotHelpful