Automated Testing The Benefits of Using Cypress for API Automation

Boosting QA Efficiency: The Benefits of Using Cypress for API Automation

In today’s fast-paced software testing environment, efficient API automation testing is crucial for ensuring the reliability and functionality of web applications. Cypress, a powerful testing framework, offers a robust solution for automating API testing with its user-friendly interface and extensive feature set.

In this blog post, we’ll provide an in-depth introduction to API automation testing using Cypress. We’ll explore the advantages of using Cypress for API testing, walk you through the setup process from installation to crafting your first test scripts, and show how Cypress can transform your API testing approach. By the end of this blog, you’ll have a solid understanding of how Cypress can enhance your API automation testing, enabling you to consistently deliver top-notch software. This guide is designed to provide testers with the essential skills and insights needed to excel in API automation testing using Cypress.

Table of Contents:

Introduction to Cypress and API Testing

Cypress is a powerful and versatile tool for web application testing that has been gaining popularity among QA engineers. Unlike traditional testing tools, Cypress is built entirely on JavaScript, offering a unique approach to directly interacting with browsers. This allows for faster and more reliable testing.

API Testing focuses on validating the functionality, reliability, performance, and security of these interfaces. Instead of using traditional user inputs and outputs, API testing involves sending calls to the API and analyzing its responses. This ensures that the systems involved communicate effectively and accurately exchange data, identifying and resolving any issues before the software is deployed.
API testing matters because APIs are like the backbone of modern apps, making sure all the different parts talk to each other properly. It checks that the application programming interface (API) does what it’s supposed to and meets user requirements. By doing this testing, we can catch any problems with the API, like wrong data formats, mistakes in responses, or security issues. Finding these problems early on helps developers fix them before they turn into big headaches.
Before diving deeper, check out our latest blog of Cypress: Cypress for Web: The Fast and Easy Way to Automate your UI  for some helpful background information.

Understanding API Automation

API automation is a crucial aspect of modern software testing that allows teams to ensure their applications meet quality standards by automating interactions with APIs.

API automation involves using software to send calls to an API, get outputs, and record the system’s response. It involves creating scripts and tools that can automatically execute tests on APIs, allowing for rapid and repetitive testing to ensure the functionality, reliability, and security of software applications.

Overall, API automation testing accelerates feedback cycles, enhances test coverage, and minimizes manual effort, contributing to the delivery of high-quality software products.

Why API Automation with Cypress?

Teams opt for Cypress in API testing due to its seamless integration, simplification of testing strategies across different layers of applications, JavaScript-based syntax, real-time in-browser testing capabilities, and unique features like time-travel debugging, offering a developer-friendly and efficient approach to testing. Cypress allows for the integration of end-to-end (E2E) and component testing with API testing within a single platform, ensuring consistency in automation strategies. With its rich set of commands specifically designed for API testing and features such as automatic waiting mechanism and real-time reloads, Cypress enhances productivity and test reliability, enabling teams to efficiently cover a wide range of functionalities and scenarios.

Moreover, Cypress brings several benefits to the forefront in API testing. Its real-time reload feature enables automatic application reloading, enhancing development and debugging efficiency. Additionally, fast test execution minimizes flakiness issues, providing quick and reliable feedback to developers. Cypress’s debugging capabilities allow for pausing and inspecting application states, simplifying the bug fixing process. The framework’s simplified syntax and built-in assertions and commands streamline test writing and organization, while parallel execution speeds up the testing process, particularly in continuous integration or delivery pipelines. Lastly, Cypress facilitates test data management, API response mocking, and status code validation, contributing to a comprehensive and efficient testing workflow.

Set up Cypress for API Automation

In this blog, we’ve implemented our examples using the following versions of libraries and applications:

  • Cypress version: 13.9.0
  • Cypress-plugin-api: 2.11.1
  • Node JS version: v20.12.2
  • Visual Studio Code version: 1.88.1

Install and Launch Cypress

  • Download and Install Node.js
  • Download and Install Visual Studio Code (VS Code)
  • Launch the Visual Studio Code and open the integrated terminal.
  • Install Cypress:
    • Type ‘npm init’ and follow the prompts or press Enter to continue, it will create a package.json file.
npm-Install
  • Next, type ‘npm install cypress –save-dev’ and hit Enter.
cypress-install
  • Launch Cypress:
    • Execute the command ‘npx cypress open’ to launch Cypress.
cypress-open
  • This will launch Cypress in headed mode.
  • Select ‘E2E Testing’ and click “Continue” on the Configuration files screen.
  • Congratulations! Your Cypress project is now set up and ready for your first test.

Install cypress-plugin-api plugin

What is cypress-plugin-api plugin?

The plugin introduces a new command, cy.api(), which functions similarly to the existing cy.request() command. However, cy.api() goes beyond making the request by displaying detailed information about the API call within the Cypress UI runner. This includes the request URL, method, headers, request body, response status, response headers, and response body.

The plugin integrates with Cypress’s time-travel debugger, allowing you to inspect API calls at any point during test execution. This can significantly aid in debugging and understanding API interactions within your tests.

request-body

Enter the following command in the terminal to install the plugin:

install-api-plugin

After the installation is complete, you can verify that cypress-plugin-api has been added to your project’s package.json file as a dev dependency.

Configure cypress-plugin-api plugin

Open the ‘e2e.js’ file in your support directory, and import cypress-plugin-api:

 //import cypress-plugin-api
 import 'cypress-plugin-api'

Now, Cypress will automatically load the cypress-plugin-api plugin whenever it runs your tests.

Writing API Tests with Cypress

Here, we will create the Test Cases for the GET,  POST,  PUT & DELETE methods.

HTTP REQUESTDESCRIPTION
POSTSubmits data for processing or creates a new resource.
GETRetrieves data from a server without modifying it.
PUTModifies or replaces an existing resource on the server.
DELETERequests removal of a resource from the server.

After the complete setup of the Cypress Project, let’s start with the API Test cases.

Create a new spec file named ‘APITests.cy.js’ in the e2e folder.

spec-file

In your Cypress.config.js file, add the following code to set the baseUrl:

//Cypress.config.js
 baseUrl: `https://fakerestapi.azurewebsites.net`, 

1️⃣GET Request Test Case

Enter the below code into your ‘APITests.cy.js’ file:

describe("Cypress API tests ", () => {
  //GET request

  it("GET request for Activities:", () => {

    cy.request({
      method: 'GET',
      url: Cypress.config('baseUrl') + '/api/v1/Activities',
    }).then((response) => {

      //Assertions
      assert.equal(response.status, 200, "status doesn't match")
      expect(response, 'has duration in ms').to.have.property('duration').and.be.a('number');
      expect(response.body[0]).to.have.property('dueDate');
      expect(response.body[0]).to.have.all.keys('id', 'title', 'dueDate', 'completed');
      expect(response.body[0]).to.contain({
        "title": "Activity 1",
      });
      assert.equal(response.body[0].id, 1, "id doesn't match")
      Cypress._.each(response.body, (responseBody) => {
        expect(responseBody.id).to.not.be.null;
        expect(responseBody).to.have.all.keys('id', 'title', 'dueDate', 'completed');
        expect(responseBody.title).to.be.a('string')
      });
    });
  })
})

This test involves a GET request to the ‘/api/v1/Activities’ endpoint, verifying that the HTTP status is 200, the response time is within limits, and the response structure includes key properties like ‘id’, ‘title’, ‘dueDate’, and ‘completed’. 

It confirms the first item’s details, such as the title “Activity 1” and id 1. The test also checks each item in the response to ensure ‘id’ fields are present, all necessary keys exist, and the ‘title’ type is a string. This test ensures not only the correct server response and data format but also the integrity of the data content.

2️⃣POST Request Test Case

Enter the below code into your ‘APITests.cy.js’ file inside describe block:

it("POST request for Activity", () => {
    cy.api({
      method: 'POST',
      url: Cypress.config('baseUrl') + '/api/v1/Activities',
      body:
      {
        "id": 2,
        "title": "Activity 2",
        "dueDate": "2024-05-08T10:55:54.7407646+00:00",
        "completed": false
      }
    }).as('postReq')

    //Assertions
    cy.get('@postReq').its('status').should('eq', 200)
    cy.get('@postReq').then((response) => {
      assert.isObject(response.body, "response body is an object")
      expect(response.body).to.have.property('id')
      expect(response.body).to.have.all.keys('id', 'title', 'dueDate', 'completed')
      expect(response.body).to.contain({
        "title": "Activity 2",
      })
      assert.equal(response.body.dueDate, "2024-05-08T10:55:54.7407646+00:00", "Due date matched")
      expect(response.body.completed).to.deep.equal(false)
      expect(response.body).to.not.be.null
    })
  })

The test begins by making a POST request to the API endpoint (/api/v1/Activities) with JSON data specifying details of an activity’s ID, title, due date, and completion status, and assigns this request the alias ‘postReq’. 

It then verifies the response by checking the HTTP status is 200, confirming the response body is an object, validating the presence and values of properties (id, title, dueDate, completed), and ensuring the response is not null, ensuring both the data structure and content are correctly handled by the API when creating new activities.

3️⃣PUT Request Test Case

Enter the below code into your ‘APITests.cy.js’ file inside describe block:

 it("PUT request for Activity", () => {
    cy.api({
      method: 'PUT',
      url: Cypress.config('baseUrl') + '/api/v1/Activities/11',
      body:
      {
        "id": 30,
        "title": "Activity 30",
        "dueDate": "2024-05-08T10:55:54.7407646+00:00",
        "completed": false
      }
    }).as('putReq')

    //Assertions
    cy.get('@putReq').its('status').should('eq', 200)
    cy.get('@putReq').then((response) => {
      expect(response.body).to.have.all.keys('id', 'title', 'dueDate', 'completed')
      assert.equal(response.body.id, 30, "Id matched")
      assert.isObject(response.body, "response body is an object")
      expect(response.body.id).to.be.a('number')
      expect(response.body.title).to.not.be.null
      assert.deepEqual(response.body.dueDate, "2024-05-08T10:55:54.7407646+00:00", "Status matched")
      expect(response.body.completed).equal(false)
    })
  })

The test executes a PUT request to ‘/api/v1/Activities/11’ with details like ID, title, due date, and completion status. The response is aliased as ‘putReq’ for easy referencing in later checks. 

These checks ensure a 200 HTTP status code and verify that the response exactly matches the keys, values, types, and data structure specified in the request. It confirms that the title is non-null and the response body is an object, accurately reflecting the expected structure post-update, confirming the API’s proper handling of data modifications.

4️⃣DELETE Request Test Case

Enter the below code into your ‘APITests.cy.js’ file inside describe block:

it("DELETE request for Activity", () => {
    cy.request({
      method: 'DELETE',
      url: Cypress.config('baseUrl') + '/api/v1/Activities/10'
    }).as('deleteReq')

    //Assertions
    cy.get('@deleteReq').then((response) => {
      expect(response.status).equal(200)
      expect(response, 'has duration in ms').to.have.property('duration').and.be.a('number');
      expect(response.body).to.be.empty
    })
  })

The test sends a DELETE request to remove an entity, presumably an “Activity” with an ID of 10, from a server. The request is then aliased as ‘deleteReq’ to facilitate later reference in assertions. This test ensures that the API endpoint not only responds correctly but also adheres to performance expectations and proper data handling after deletion.

Execute Tests and Analyze Results

Execute Tests

  • Run the command ‘npx cypress open’ in your VS Code terminal:
run-result
  • Choose ‘E2E Testing’ > Click on ‘Chrome’ browser > Click on your spec file ‘APITests.cy.js’ and click on it
test-runner
  • Now, you can see your API tests running in the Cypress Runner successfully.

Analyze the result

For API tests, you can see detailed request and response logs in the Cypress Test Runner UI. This includes the URL, method, request headers, response headers, status code, response body, and more.

Review the assertions for each API call. Cypress will clearly show which assertions have passed or failed. For example, it will show if the expected status code was received, if the response matches expected values, etc.

For the API tests example mentioned above, here are the results we can see for each requests:

GET Request Test Case:

get-req-result

POST Request Test Case:

post-req-result

PUT Request Test Case:

put-req-result

DELETE Request Test Case:

delete-req-result

Best Practices for API Automation with Cypress

Use Custom Commands for API Requests

When you have an API call which needs to be called across many test cases, then you can create your own custom command with Cypress and use it across many spec files. For example,

Place the below custom command definition in a Cypress support file ‘cypress/support/commands.js’.

Cypress.Commands.add('ApiRequest', (method, endPoint, body) => {
    cy.request(method, Cypress.config('baseUrl') + endPoint, body)
})
  • Cypress.Commands.add(): This method is used to define a custom Cypress command.
  • ‘ApiRequest’: This is the name of the custom command being created.
  • ‘method’: Represents the HTTP method (e.g., GET, POST, PUT, DELETE) to be used for the request.
  • ‘endPoint’: Specifies the endpoint or URL of the API that the request will be sent to.
  • ‘body’ (optional): Represents the payload or body of the request. This parameter is optional and may be omitted if the request doesn’t require a body (e.g., GET requests).
  • ‘cy.request()’: This is the built-in Cypress command used to make HTTP requests.
  • Cypress.config(‘baseUrl’) + endPoint: Combines the base URL retrieved from Config file  with the endpoint to form the complete URL for the API request.

You can use this custom command inside you spec file, which will look like below:

 it("GET request for Activities:", () => {
    cy.ApiRequest('GET', `/api/v1/Activities/`).then((response) => {
assert.equal(response.status, 200, "status doesn't match")
  });
  })

Use Aliases for Reusability

Aliases in Cypress allows you to store references to DOM elements, HTTP requests, and responses, making your tests more readable, maintainable, and efficient. Use aliases with API responses to extract and reuse data, or to perform assertions. For example,

it("POST request for Activity", () => {
    cy.api({
      method: 'POST',
      url: Cypress.config('baseUrl') + '/api/v1/Activities',
      body:
      {
        "id": 2,
        "title": "Activity 2",
        "dueDate": "2024-05-08T10:55:54.7407646+00:00",
        "completed": false
      }
    }).as('postReq')

    //Assertions
    cy.get('@postReq').its('status').should('eq', 200)
 })

Here we have made a POST request to create an activity (/api/v1/Activities) and alias the response as ‘postReq’. response is aliased, the test performs assertions on the response. It checks whether the status code of the response is equal to 200. This approach allows for cleaner and more readable test code, as well as promoting reusability if the response data needs to be used in subsequent test steps.

Use fixtures for POST and PUT req data

Keeping the request data separate from the test code helps maintain a clear separation of concerns. Fixtures allow you to define data independently from your test logic. Fixtures can be reused across multiple tests.

Here’s how you can use fixtures for POST request data in Cypress API test:

Start by creating fixture files for your request data. These can be JSON files containing the payload for your POST request.Create a new file ‘postData.json’ inside fixtures folder. Place the below code inside your ‘postData.json’ file:

{
  "id": 2,
  "title": "Activity 2",
  "dueDate": "2024-05-08T10:55:54.7407646+00:00",
  "completed": false
}

In your Cypress test code, load the fixture data using the cy.fixture() command.

 it("POST request for Activity", () => {
    cy.fixture('postData.json').then((postData) => {
      cy.ApiRequest('POST', '/api/v1/Activities/', postData).as('postReq')
      cy.get('@postReq').its('status').should('eq', 200)
 })
  })

Handle API Response with Assertions

Make full use of Cypress’s promise-like chaining and assertions to handle API responses effectively.

Always verify the structure of the API response to ensure that it meets the expected schema. This includes checking that all expected fields are present and have the correct data types.

Validate that the API returns the correct HTTP status codes for various scenarios (success, error, unauthorized, etc.).

Ensure that the API responses are within acceptable time limits to check performance.

Avoid Unnecessary Waits

The concept of avoiding unnecessary waiting in Cypress testing revolves around optimizing test efficiency and reliability by eliminating the use of arbitrary time-based waits like cy.wait() and instead utilizing route aliases or assertions to synchronize test execution with specific conditions. 

Use assertions like should() to wait for specific conditions to be met, such as the presence of an element or the expected response from an API call.

Cypress automatically retries assertions until they pass or a timeout occurs. This helps in handling asynchronous behavior without the need for manual waiting.

Conclusion

Integrating Cypress for API automation offers numerous advantages while presenting a few considerations to keep in mind. Cypress offers a user-friendly testing experience with its well-designed framework and extensive resources. Its ability to handle both API and UI testing in one platform promotes efficiency and teamwork. Additionally, Cypress’s rich set of built-in assertions, network stubbing capabilities, and real-time debugging features empower testers to create reliable and maintainable API test suites.

However, it’s essential to acknowledge some potential drawbacks. Cypress’s focus on front-end testing means that its API testing functionalities might not be as extensive or mature as specialized API testing tools. Cypress relies heavily on JavaScript, which means that teams unfamiliar with the language may face a learning curve when adopting Cypress for API automation. Cypress is designed to run tests within a browser environment, which might not always align with certain scenarios where API testing needs to be performed outside of the browser context or in non-web environments. Compared to more established API testing frameworks and tools, Cypress’s community and support ecosystem might be relatively smaller. This could mean fewer readily available resources, community plugins, or community-driven support channels for troubleshooting issues or seeking guidance on complex API testing scenarios.

In Conclusion, with its user-friendly interface, powerful capabilities, and seamless integration with existing workflows, Cypress stands as a compelling option for enhancing the efficiency and effectiveness of API testing processes. As organizations continue to explore modern testing solutions, Cypress remains a compelling option for ensuring the effectiveness of API testing practices.

Keep practising and exploring to master these powerful tools further with Jignect

Witness how our meticulous approach and cutting-edge solutions elevated quality and performance to new heights. Begin your journey into the world of software testing excellence. To know more refer to Tools & Technologies & QA Services.

If you would like to learn more about the awesome services we provide, be sure to reach out.

Happy testing! 🙂