DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Get Some Rest! A Full API Stack
  • Architecting a Comprehensive Testing Framework for API and UI Testing
  • Cypress API Testing: A Detailed Guide
  • API Testing With Cypress

Trending

  • The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins
  • Enforcing Architecture With ArchUnit in Java
  • How To Build Resilient Microservices Using Circuit Breakers and Retries: A Developer’s Guide To Surviving
  • The Future of Java and AI: Coding in 2025
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Cypress Best Practices for API Test Automation

Cypress Best Practices for API Test Automation

Learn how to automate APIs using Cypress, how to automate APIs using an API plugin and learn API automation best practices.

By 
Kailash Pathak user avatar
Kailash Pathak
DZone Core CORE ·
May. 01, 23 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
3.7K Views

Join the DZone community and get the full member experience.

Join For Free

API Automation refers to the process of automatically testing and verifying the functionality of Application Programming Interfaces (APIs) to ensure that they are working as expected.

This blog covers the following:

  1. How to Automate APIs using Cypress
  2. How to Automate APIs using API plugin “cypress-plugin-api” by Filip Hric
  3. Cypress API Automation best practices

What Is API Automation?

API Automation refers to the process of automatically testing and verifying the functionality of Application Programming Interfaces (APIs) to ensure that they are working as expected.

API Automation is typically done using software tools that automate the process of sending requests to the API, analyzing the responses, and comparing them to the expected results. The goal of API automation is to reduce the time and effort required to manually test APIs and to increase the reliability and consistency of the testing process.

What Is a REST API?

REST API stands for Representational State Transfer API, which is a web standards-based architecture for building web services. It is a common way of communicating between clients and servers over the Internet.

REST APIs use HTTP requests to POST (create), PUT (update), GET (read), and DELETE (delete) data. API automation allows for efficient and thorough testing of REST APIs by making multiple API calls and verifying the responses. This can help to identify and resolve bugs and issues early on in the development process

Example To Explain REST API

Suppose you have a website that lists information about books, and you want to allow other applications to retrieve information about books from your website. You can build a REST API for this.

Here’s how it could work:

  1. Endpoint: A client application would make a request to a specific URL, known as an endpoint, that represents a collection of books. For example.
  2. HTTP Methods: The client would use one of the following HTTP methods to make a request:
  • GET: To retrieve information about a book or a collection of books.
  • POST: To add a new book to the collection.
  • PUT: To update information about a book.
  • DELETE: To remove a book from the collection.

Response: The server would respond with data in a specific format, such as JSON, that the client can use to retrieve the information about books.

For example, a client could make a GET request to retrieve a list of all books in the collection. The server would respond with a JSON payload that includes information about each book, such as its title, author, and ISBN number.

In this example, the REST API provides a way for client applications to interact with the website’s data about books in a standardized, programmatic way.

Cypress For API Automation

Cypress is a JavaScript-based end-to-end testing framework for web applications. It allows you to write tests for your application’s UI as well as its APIs. Here’s an example of how you could write a test for an API using Cypress.

Here is a basic example of using Cypress for API automation:

  1. Install Cypress: npm install cypress --save-dev
  2. Create a test files for GET,POST,PUT and DELETE Method under cypress/e2e/cypress_api_tc.cy.js

Let's see how GET methods work here to fetch the user’s detail.

GET Method

JavaScript
 
it("GET API testing Using Cypress API Plugin", () => {
    cy.request("GET", "https://reqres.in/api/users?page=2").should((response) => {
      expect(response.status).to.eq(200);
    });
  });


POST Method

Let's see how the POST methods work. Here we are creating a new user.

JavaScript
 
  it("POST API testing Using Cypress API Plugin", () => {
    cy.request("POST", "https://reqres.in/api/users", {
      name: "Kailash P",
      job: "QAAutomationLabs",
    }).should((response) => {
      expect(response.status).to.eq(201);
    });
  });


Let's see how the PUT methods work. Here we are updating the user’s detail.

PUT Method

JavaScript
 
 it("PUT API testing Using Flip Plugin", () => {
    cy.request("PUT", "https://reqres.in/api/users/2", {
      name: "QAAutomationLabs",
      job: "QA Automation Engg",
    }).should((response) => {
      expect(response.status).to.eq(200);
    });
  });


Let's see how the DELETE methods work. Here we are deleting the user’s detail.

Delete Method

JavaScript
 
  it("DELETE API testing Using Cypress API Plugin", () => {
    cy.request("DELETE", "https://reqres.in/api/users/2").should((response) => {
      expect(response.status).to.eq(204);
    });
  });


In this example, the cy.request() function is used to send the request to the endpoint. The response from the API is stored in the response variable and can then be used to write assertions using Chai.js.

The Output of Execute Test Cases

The Output of Execute Test Cases

API Automation Using Plugin ‘Cypress-Plugin-Api’

Cypress plugin for effective API testing. Imagine Postman but in Cypress. Prints out information about the API call in the Cypress App UI.

The benefit of using the plugin:

  • In cypress-plugin-api, we have the command cy.api() work almost similar to cy.request() the main difference is that in cy.api() in addition to calling your API, it will print our information about the API call in your Cypress runner.
  • All of the info can be viewed in time-travel snapshots
  • Simple table for viewing cookies
  • JSON data object and array folding
  • Color coding of methods in UI view and in the timeline

Good Part is cy.api() function actually uses cy.request in the background, so it’s exactly the same thing plus visual UI.

Set-up Cypress-Plugin-API

Below are the steps to set up the plugin.

For more detail, please follow the link.

Step 1

Install the plugin using npm or yarn. Below is the command:

npm i cypress-plugin-api # or yarn add cypress-plugin-api

Once the API plugin is installed can be seen in package.json.

package.json


Step 2

Import the plugin into your cypress/support/e2e.js file:

import ‘cypress-plugin-api’ // or require(‘cypress-plugin-api’)

e2e.js files look like the attached ones below.

Step 3

Create cypress_plugin_api.cy.js with Methods (GET, POST, PUT, DELETE)

For demo purposes, I am taking various API method examples from this site.

GET Request

JavaScript
 
it("GET API testing Using Cypress API Plugin", () => {
  cy.api("GET", "https://reqres.in/api/users?page=2").should((response) => {
    expect(response.status).to.eq(200);
  });
});


POST Request

JavaScript
 
it("POST API testing Using Cypress API Plugin", () => {
  cy.api("POST", "https://reqres.in/api/users", {
    name: "morpheus",
    job: "leader",
  }).should((response) => {
    expect(response.status).to.eq(201);
  });
});


PUT Request

JavaScript
 
it("PUT API testing Using Cypress API Plugin", () => {
  cy.api("PUT", "https://reqres.in/api/users/2", {
    name: "morpheus",
    job: "zion resident",
  }).should((response) => {
    expect(response.status).to.eq(200);
  });
});


DELETE Request

JavaScript
 
it("DELETE API testing Using Cypress API Plugin", () => {
  cy.api("DELETE", "https://reqres.in/api/users/2").should((response) => {
    expect(response.status).to.eq(204);
  });
});


Step 4: API Test Case Execution Report

In the below screenshot, we can see the data of Body, Response, Headers, and Cookies in Cypress App UI.

Earlier, we have to click on inspect to see all this information, but now we have UI to see all this information.

GET Request

data of Body, Response, Headers, and Cookies in Cypress App UI

POST Request

data of Body, Response, Headers, and Cookies in Cypress App UI

PUT Request

data of Body, Response, Headers, and Cookies in Cypress App UI

DELETE Request

data of Body, Response, Headers, and Cookies in Cypress App UI


Cypress API Automation Best Practices

API Automation Best Practices are guidelines and techniques that help ensure the reliability, maintainability, and efficiency of API tests.

Some of the best practices for API Automation are:

1. Keep Tests Atomic and Independent

When tests are atomic and independent, they are more reliable and less prone to failures caused by the interactions between tests. This makes it easier to isolate and debug failures, as you can run the failing test on its own and not be affected by other tests.

JavaScript
 
describe('API Test Suite', () => {
  beforeEach(() => {
    cy.request('GET', '/reset');
  });
  
  it('Get User Information', () => {
    cy.request('GET', '/users/1')
      .its('body')
      .should('include', { id: 1, name: 'John Doe' });
  });
  
  it('Create a User', () => {
    cy.request('POST', '/users', { name: 'Jane Doe' })
      .its('body')
      .should('include', { id: 2, name: 'Jane Doe' });
  });
});


In this example, the beforeEach block resets the data before each test, which ensures that tests are isolated from each other and do not affect the outcome of other tests.

2. Use Fixtures To Mock API Responses

Fixtures are a way to store external data that can be used in the tests. This allows you to keep the test data separate from the test code, making it easier to maintain and reuse.

Cypress provides the cy.fixture() command to load data from a fixture file and use it to mock API responses.

JavaScript
 
// cypress/fixtures/example.json
{
  "data": [
    { "id": 1, "name": "John Doe" },
    { "id": 2, "name": "Jane Doe" }
  ]
}


JavaScript
 
describe('Example API test', () => {
  it('Loads mock data from fixtures', () => {
    cy.server();
    cy.route('GET', '/api/example', 'fixture:example.json').as('example');

    cy.visit('/');

    cy.wait('@example')
      .its('response.body')
      .then((body) => {
        expect(body.data[0].id).to.equal(1);
        expect(body.data[0].name).to.equal('John Doe');
      });
  });
});


In this example, the cy.fixture() method is used to load a JSON file containing user data, and the data is stored as an alias usersJSON. The response body is then asserted to deep equal the first user in the JSON file.

3. Use Environment Variables for Configuring API Endpoint

You should use environment variables to configure the API endpoint URL and other test data that you use in your test cases. This makes it easier to manage and maintain your test suite, and allows you to change the data without modifying the code.

Store the API endpoint URL in a .env file in the root of your project

JavaScript
 
API_BASE_URL=https://api.example.com


In your cypress.json file, add the following configuration to make the environment variables accessible in your tests

JavaScript
 
{
  "env": {
    "API_BASE_URL": "https://api.example.com"
  }
}


Access the API endpoint URL in your tests using Cypress.env()

JavaScript
 
const apiBaseUrl = Cypress.env('API_BASE_URL');
describe('Books API', () => {
  it('Retrieves a list of books', () => {
    cy.request(`${apiBaseUrl}/api/books`)
      .its('body')
      .should('be.an', 'array')
      .and('have.length.greaterThan', 0);
  });
});


4. Use Yup Library Schema Builder

Sometimes the data we received in API response is dynamic, so making assertions on dynamic data is not easy. In that case, we can use the Yup library/

The Yup library can be used in API automation to validate the data received from an API response against a defined schema. This ensures that the data received from the API is in the expected format and meets the required constraints.

Here is an example of how to use Yup in Cypress API automation:

JavaScript
 
import axios from 'axios';
import * as yup from 'yup';

const personSchema = yup.object().shape({
  name: yup.string().required(),
  age: yup.number().required().positive().integer(),
  email: yup.string().email().required(),
});

describe('API test', () => {
  it('validates person data received from API', () => {
    cy.request('GET', 'https://api.example.com/person')
      .then((response) => {
        const person = response.body;
        
        try {
          personSchema.validateSync(person);
          console.log('The data received from the API is valid!');
        } catch (err) {
          console.error('The data received from the API is invalid: ', err.message);
        }
      });
  });
});


In this example, the test uses the cy.request command to make a GET request to the API endpoint and retrieve the person data. The response data is then validated against the personSchema using the validateSync method. If the data is valid, a message is logged to the console. If the data is invalid, an error message is logged to the console with the validation error.

5. Use Cypress.Commands

Cypress provides a convenient way to define custom commands to be reused across multiple test cases. This can help in reducing code duplication and making the tests more readable.

Example: Use Cypress.Commands.add to create a custom command to make API calls and to assert the response.

JavaScript
 
Cypress.Commands.add('apiCall', (url, method, data) => {
  return cy.request({
    method: method,
    url: url,
    body: data
  }).then((response) => {
    return response;
  });
});

// Use the custom command in a test
it('Test API', () => {
  cy.apiCall('/api/v1/data', 'GET')
    .its('body')
    .should('include', { data: 'Sample Data' });
});


6. Cover Positive and Negative Test

Cypress provides a variety of methods for validating API responses, including its(“body”) and its(“status”). These methods allow you to inspect the response from an API request and make assertions about its contents. Here’s an example of validating positive and negative API responses

JavaScript
 
describe('Test API response', () => {
  it('handles positive response', () => {
    cy.request('GET', 'https://jsonplaceholder.typicode.com/posts/1')
      .its('body')
      .should('have.property', 'id', 1)
      .should('have.property', 'title', 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit')
  });

  it('handles negative response', () => {
    cy.request({
      method: 'GET',
      url: 'https://jsonplaceholder.typicode.com/posts/0',
      failOnStatusCode: false
    }).then((response) => {
      expect(response.status).to.eq(404)
      expect(response.body).to.be.empty
    })
  });
});


In the first test, we’re making a GET request to an endpoint that should return a positive response, and we’re checking that the response body has certain properties.

In the second test, we’re making a GET request to an endpoint that should return a 404 status code, indicating a negative response

7. Debugging

Use Cypress debugging features such as the browser dev tools and the cy.debug() command to quickly diagnose and fix issues.

JavaScript
 
describe('Get user details', () => {
  it('should return user details', () => {
    cy.request('GET', 'https://jsonplaceholder.typicode.com/users/1')
      .its('body')
      .then(userDetails => {
        cy.log(userDetails);
        cy.debug();
      })
      .should('include', {
        id: 1,
        name: 'Leanne Graham',
        username: 'Bret',
        email: 'Sincere@april.biz',
      });
  });
});


In this example, the cy.request() command is used to make a GET request to the specified API endpoint. The response is then logged to the console using cy.log(). Finally, the cy.debug() command is used to stop the test and open the debugger, allowing you to inspect the response and debug any issues.

8. Use Cy.Intercept()

The cy.intercept() command in Cypress allows you to intercept and modify network requests made by your application. This can be useful for API automation, as it allows you to control the response that is returned to your application and test how it handles different scenarios.

Here’s an example of using cy.intercept() in Cypress API automation

JavaScript
 
describe('Save User', () => {
  it('displays a success message when the user is saved', () => {
    cy.intercept('/api/save-user', {
      method: 'POST',
      response: { success: true },
    }).as('saveUser');

    cy.get('[data-cy=save-button]').click();

    cy.wait('@saveUser');

    cy.get('[data-cy=success-message]').should('be.visible');
  });

  it('displays an error message when the user is not saved', () => {
    cy.intercept('/api/save-user', {
      method: 'POST',
      response: { success: false },
    }).as('saveUser');

    cy.get('[data-cy=save-button]').click();

    cy.wait('@saveUser');

    cy.get('[data-cy=error-message]').should('be.visible');
  });
});


In this example, the cy.intercept() command is used to intercept the API call to /api/save-user with a POST method. The response property is set to an object with a success property, which will be returned to the application when the API call is made. The .as() method is used to give the intercept a name, which can then be used with cy.wait() to wait for the intercept to complete before making assertions about the state of the application.

9. Implement Error Handling to Gracefully Handle Unexpected Errors

Your automation test suite should include error handling to gracefully handle unexpected errors. This helps you avoid the test suite crashing or failing when an unexpected error occurs.

Here’s an example of how you can handle unexpected errors in Cypress when making an API call:

JavaScript
 
cy.request({
 method: 'GET',
 url: 'https://example.com/api/endpoint'
}).then((response) => {
 if (response.status === 500) {
 console.error('Unexpected error:', response.body)
 } else {
 // continue with the test
 }
}).catch((err) => {
 console.error('Request failed:', err)
})


In this example, if the API returns a status code of 500, it means that an unexpected error has occurred, and the error message is logged to the console. If the request fails entirely, the error is caught by the catch block and also logged to the console. You can customize this code to fit your specific error-handling needs.

10. Make Use of Logging to Trace Errors and Debugging Information

You should include logging in to your automation test suite to trace errors and debugging information. This helps you understand what went wrong when a test fails and makes it easier to debug the problem.

For example, you could log the request and response data for each test case so that you can see what was sent and received during each test.

Here’s an example of how you can log information about an element:

JavaScript
 
cy.get('#element').then((element) => {
 console.log('Element text:', element.text())
 console.log('Element width:', element.width())
 console.log('Element height:', element.height())
})


Here’s another example of how you can log information about a response from an API call:

JavaScript
 
cy.request({
 method: 'GET',
 url: 'https://example.com/api/endpoint'
}).then((response) => {
 console.log('Response status:', response.status)
 console.log('Response body:', response.body)
})


Let’s Login To Application Using API (Best Practices)

Suppose you have a test that verifies that a user can log in to your application using the API.

A possible implementation using these best practices would look like this

JavaScript
 
describe('Login', () => {
  beforeEach(() => {
    cy.fixture('user.json').as('user');
  });

  it('should log in successfully', () => {
    cy.request({
      method: 'POST',
      url: `${Cypress.env('apiUrl')}/login`,
      body: {
        email: this.user.email,
        password: this.user.password,
      },
    }).then((response) => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('token');
    });
  });
});


In this example, the fixture user.json is loaded with cy.fixture() and stored as this.user for later use. The Cypress.env() method is used to retrieve the URL for the API from an environment variable. The test uses cy.request() to make a POST request to the /login endpoint with the user's email and password and then uses expect() to verify that the response has a status code of 200 and contains a token property.

Wrapping Up

Cypress can be used for API automation by making HTTP requests to your application’s APIs and asserting that the responses meet the expected criteria. The Cypress test runner provides a convenient API for making requests and evaluating responses, allowing you to write end-to-end tests that cover both the front-end and back-end of your application.

API API testing HTTPS REST Testing

Published at DZone with permission of Kailash Pathak. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Get Some Rest! A Full API Stack
  • Architecting a Comprehensive Testing Framework for API and UI Testing
  • Cypress API Testing: A Detailed Guide
  • API Testing With Cypress

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!