CHAPTERS
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.
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.
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.
Run Cypress test scripts across 50+ browsers and operating systems. Try LambdaTest Now!
In the context of Cypress automation, exceptions can occur for various reasons. Below are the most common types of exceptions in Cypress:
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.
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.
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" );
});
})
When you run the above test case, you would see the result just like shown below:
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.
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, })
}) })
To prevent API from failing on bad status code, you must pass option object failOnStatusCode:false to cy.request().
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:
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.
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.
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.
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.
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.
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:
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.
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:
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.
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:
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:
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.
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.
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.
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.
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.
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.
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.
Now, re-run the test case, and you will observe the test execution will not fail.
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.
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.
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.
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.
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
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.
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).
Get 100 minutes of automation test minutes FREE!!