How to do Cypress API testing
April 17, 2024

How to Do Cypress API Testing

API Testing

In the ever-evolving landscape of web development, enabling applications to function correctly and deliver a seamless user experience is paramount. This is where Cypress, a next-generation front-end testing tool built for the modern web, comes into play. 

In this blog, we will go over the advantages of testing with Cypress, how to get started with Cypress API testing, and some key features to be aware of as you execute your tests.

Back to top

Mastering In-Browser Testing: Cypress's Unique Advantage

Unlike other testing frameworks that operate by running outside the browser and executing remote commands across the network, Cypress runs right inside the browser. This allows for faster, more reliable, and more realistic interaction testing for anything built on the web.

Cypress is designed to handle the complexities of modern JavaScript-heavy applications, with a unique DOM manipulation technique and a set of rich APIs. 

It provides developers and QA engineers with a robust testing environment that is both developer-friendly and capable of handling the intricacies of asynchronous operations, a common challenge in web applications.

Experience better Cypress API testing with BlazeMeter and Perfecto. Schedule a custom demo today to see how we can address your unique needs.

Request Demo

Ease of setup, clear documentation, and a strong community contribute to Cypress's growing popularity. This testing framework empowers developers to write various types of tests, such as end-to-end tests, integration tests, and unit or component tests, providing immediate visual feedback and a plethora of troubleshooting tools. 

It goes without saying that Cypress is an invaluable asset in modern Web development. Yet, when it comes to integrating it with API endpoints for comprehensive testing, one might find themselves pondering the optimal approach.

Back to top

Key Cypress API Testing Features

Time Travel

Cypress's Time Travel feature offers a unique debugging perspective. It allows us to step back through the sequence of events that occurred during test execution and check what happened with the data from a request and its response.

Real-Time Reload

Cypress monitors for any changes in your test code and automatically refreshes the tests, rerunning them instantly to get feedback as soon as possible.

Request Interception

Cypress can intercept network requests by matching routes. This way, we can test our application's reaction to diverse scenarios such as server outages, delayed responses, or unexpected data structures. 

While valuable for API testing, its utility extends beyond that to a broader range of testing contexts.

Stubbing Responses

Stubbing responses is a game-changer when it comes to testing your application, allowing simulation of conditions difficult to reproduce with a real server. 

This enables us to try edge cases that are challenging to execute under normal circumstances.  It's important to note that stubbing is not exclusively for API testing and should not be confused with mocking. 

Alias and Custom Commands

By assigning an alias to network interceptions or commonly used elements, we create shorthand references that enhance test readability and maintenance. Similarly, Custom Commands allows us to encapsulate complex sequences of actions into reusable functions.

BDD Style With Simple Assertions

Cypress harnesses the strengths of both Mocha and Chai to provide a testing experience that is both developer-friendly and potent in its capabilities. Mocha's behavior-driven development (BDD) style syntax lays the groundwork for structuring tests while Chai's assertion library offers a comprehensive suite of self-explanatory assertions.

Developer Experience

The Test Runner UI allows developers to see tests run in real-time within the context of their application. They can interact with the rendered application, inspect the application's state at any point in the test, and directly observe network requests and responses. 

Back to top

How to Get Started with Cypress API Testing

  1. Installation

To install Cypress, first install Node.js as a prerequisite, preferably in its LTS release. We can also check further supported versions and additional system requirements in this section.

After this step is done, we should be able to check Node and NPMs versions with the following commands. Otherwise, we might need to look into your system environment variables to check the binaries path is properly set up.

Showing versions of Node (20.11.0) and NPM(10.2.4)

The next step is to initiate a Node.js project. Inside your project directory, use the ‘npm init’ command. We can leave all the prompting fields blank as all of this data will go into the ‘package.json’ file. 

After that, use ‘npm install cypress --save-dev’ to install Cypress as a dev dependency. Your ‘package.json’ should look like this:

Package.json file with Cypress in devDependencies

Then, by using the ‘npx cypress open’ command, we can open the Cypress Test Runner UI and configure the framework according to your needs, such as sort of testing, desired browser, etc. 

Afterward, from the browser of your choice, this interface lets us include different examples to try the features or write your own tests, which will appear in the Spec section, ready to be run whenever we like.

Cypress Test Runner UI in Specs tab

For more information on how to install and set up Cypress in different ways, there is the official documentation.

  1. Writing Tests and Assertions

Let us go ahead and write some tests, shall we?

First of all, we need to define which API we will be using, so we’ll choose GoRest. For this platform, we’ll require an access token that allows us to create, update, and delete data. That's our next step, and we can quickly obtain this token by logging in with a Microsoft, GitHub, or Google account and have it created in an instant.

Go REST Access Tokens view

Afterward, we will include the key as an environment variable when we start Cypress with this command:

 

npx cypress open --env API_KEY=<TOKEN>

 

Bear in mind that we are setting our key with the --env flag, but these variables can be set in other ways. For more information, check this link

With our API KEY set, now we can try any of the endpoints.

Take a look at the code below. We have defined an error to be raised if the API Key is not set, followed by a GET request that targets the /users endpoint. To ensure it points to the full endpoint as desired, “https://gorest.co.in/public/v2/users”, we have set the baseUrl property in the config file.

<Code Snippet: ‘Cypress Config’>

For this particular case, we don’t have to send the access token because getting all users doesn’t have that requirement. However, we still perform assertions on its content, which is visible within the then command. 

Observe how we use the command with a callback function as a parameter, allowing us to write multiple assertions in this block.  It's also important to note that we have to use the wrap command to make the response chainable with the should command. 

<Code Snippet: ‘users_tests.cy.js’ only “Should Get All Users” >

In the next example, we are using the should command to handle the response in the callback function. Yet, wrapping the response and chaining a should would not work properly. 

This happens because  .should() is designed to retry assertions. If a Cypress command is used inside the callback, it would attempt to re-add that command to the queue every time it retries. This can lead to unexpected behavior and potential command duplication. 

In turn, we use only the expect commands in this example:

<Code Snippet: ‘users_tests_should_callback.cy.js’>

Last but not least, in this other example, we showcase how to use a single assertion when our goal is simply to validate the status code, for instance:

<Code Snippet: ‘users_tests_should_no_callback.cy.js’>

  1. Running Tests

In order to execute the tests, we can do so as many times as we want from the Cypress UI, or we can use the npx cypress run command.  To run a specific spec, we can pass along the -s or –spec flag along with the path to the file,   and in our case the -e or –env flag to send our API key. So it should look like this when we trigger the command from our terminal:

Users Suite execution status with all details after run command
  1. Features

Let’s examine our other users' test cases so that we have all CRUD operations with users. This will give us a total of five test cases, as shown in the snippet below. In the end, we use other methods such as POST, PATCH, and DELETE, whether sending the access token inside the headers or sending a payload in the request body.


<Code Snippet: ‘users_tests.cy.js’ all cases>

Test Get User Request with user ID showing data from request and response

BDD Syntax

Observing the “Get All Users” case shown, we find different validations in place, such as the status code, the body type, and length, and the headers content type response. These are carried out using assertion commands, and we can add as many as needed within the callback function. Furthermore, it’s evident that the commands employ the BDD style syntax provided by Mocha and Chai, which are libraries incorporated in Cypress.

Developer Experience

If we take a look at the Test Runner UI with this code, we can observe that whenever we select a spec to run, the information about the test and its various steps appears in the left section. This area displays the file name, the name of the Test Suite, and the specific tests defined, along with their status. Additionally, we can view the test body, which contains all the included steps and assertions.

We can also see other details such as the number of tests passed and failed, total time elapsed, and rerunning all tests.

Time Travel

The middle section is where the web application UI would be displayed if we were testing at that level, but since that's not our focus here, we'll skip it. The right section contains the DevTools console, which we can open to inspect the data being handled or validated at any given moment. 

This is possible thanks to the Time Travel feature. Not only does this record the data at that step but also takes a snapshot of the state of the application at that point, allowing for a thorough review if anything goes awry.

Time Travel Feature showing assertion performed

Real-Time Reload

With the Real-Time Reload feature, we can see our application change in real time as we hit the save hotkey, even if we have not made any changes to our code.

Request Interception

Now let’s add some other examples to our code and try out other features from Cypress we have not seen yet.

Let’s define another suite in which we are going to try Request Interception and Stubbing its Response. Keep in mind that although this is not strictly API testing, it is closely related as we can assert the content of both request and response triggered by a UI interaction. 

Be mindful that in case we define the request on our end, we don't need to intercept anything because the request method allows us to work directly with the API. 

Take a look at the following code, we are going to intercept the GET request, with a custom timeout, when we perform a user search in this simple appThis app retrieves data from the GitHub API so that we can validate data involved in both the request and the response.

<Code Snippet: ‘intercept_request.cy.js’ “Should Intercept The User Search”>

Stubbing Responses

Next, we'll conduct a test where we modify the response from one of the endpoints to observe how the web application handles various conditions. This approach is a practical method for testing edge cases that might be infrequent in a production environment.

The next example shows a custom response in which the intercepted request’s body has been replaced by an empty object, so many of the fields have no data. 

As a result, in the following requests triggered they are targeting an endpoint with an “undefined” username. Therefore, we can infer from this that those subsequent requests depend on the username retrieved from the first request. 

<Code Snippet: ‘intercept_request.cy.js’ “Response With Empty Body”>

Sending an empty body in the first of a chain of requests, the following requests carry an undefined value as a result

There are additional methods to intercept and stub responses that enable us to simulate various scenarios, including:

  • Forcing a network error
    <Code Snippet: ‘intercept_request.cy.js’ “Force Network Error”>
Force network error effect in test
  • Replacing partially the response data such as the avatar, profile URL, and username
    <Code Snippet: ‘intercept_request.cy.js’ “Stub Response Of First Follower”>
Changing URL, avatar, and username in data from response
  • Replacing the body with a fixture stored in the project
    <Code Snippet: ‘intercept_request.cy.js’ “Fixture”>

Wrapping Up

To summarize our key takeaways, we can conclude that:

  1. The second argument of the request method allows us to tailor the intercepted request’s response, whether defined within the code or via an external file.
  2. We can test the application’s behavior whenever there are network errors by simulating them.
  3. It's possible to partially modify the response data to try specific changes in the payload

This Cypress documentation offers more information on intercepting and stubbing.

Aliases and Custom Commands

We have already seen how to assign an interception of a request with an alias, but we can do so as well with variables, fixtures, or any other sort of data that we wish to call easily by its name. Usually, it is assigned in a before-hook and called from the test afterward. 

Let us go ahead and try to wrap up our previous ‘Get All Users’ request with an alias so we can call the users list at our convenience.

<Code Snippet: alias_commands.cy.js’ “Should Retrieve Users Through A Request With Alias” + beforeEach>

Alias “getUsersList” displayed in the request

Here we have assigned the request under the getUsersList alias. Then, we validate some things that we have already covered in our other test, but this time we add a loop to check that every element in the body must have an id.

Now for our final demo, let’s create a custom command that calls the new user endpoint. This command must be defined in the commands.js file.

<Code Snippet: alias_commands.cy.js’ “Should Create a User with Custom Commands”>

Create User POST Request called in Custom Command

<Code Snippet: ‘support/commands.cy.js’>

Then we can add a JS doc to have a brief description of our custom command:

<Code Snippet: ‘support/commands.d.ts’>

JS Doc displayed in newUser command suggestion

More information on Aliases and Custom Commands can be found below:

Back to top

Bottom Line

As we have journeyed through the capabilities of Cypress API testing, it's clear that it stands as a robust tool in the developer's toolkit. From crafting custom commands to intercepting and modifying requests and responses on the fly, Cypress enables us to simulate real-world scenarios and validate application behavior efficiently.

The ease of writing tests offers an unparalleled testing experience that not only boosts productivity but also enhances the quality of the end product. By embracing the full spectrum of Cypress’s features, developers and testers alike can boost their applications to be robust, resilient, and ready for the demands of modern users.

BlazeMeter’s API testing and monitoring capabilities are unrivaled in the market because  we deliver rigorous API validation and real-time monitoring that ensures seamless integration and functionality of services in complex systems.​

For those ready to deepen their mastery of Cypress or embark on the path of intuitive and comprehensive testing, the resources and community are waiting. Dive in, and watch your applications thrive in an ecosystem built for success. Users can utilize previously created API tests in production by simply changing data- no need to do the work twice.​

If you are ready to begin Cypress API testing, why not use the best API testing and monitoring tool on the market? Get started with BlazeMeter for FREE today!

Start Testing Now

Back to top