End-to-end Testing
How-tos & Guides
5 min read

API testing in Cypress

Learn how to create API tests using the Cypress testing framework.

Priscy Ikechi
Published September 22, 2022

APIs form the foundation of most modern-day web applications, delivering data to the client-side code which is then parsed and rendered in the UI. Since most UI interactions operate on data retrieved from an API, you can think of end-to-end tests (i.e. tests that use your UI to replicate user workflows) as implicitly testing your API as well.

There are definitely cases where we’ll want to write tests against our APIs directly, but when thinking about doing API testing in addition to end-to-end testing, a key principle to consider is to avoid duplicative tests. We provide the following advice in our regression testing guide:

If you duplicate the same workflows across multiple tests, you’ll need to make the same updates in each of those tests when your application changes. Workflows that appear in multiple tests should be managed in a single location and referenced by other tests. Other workflows should be tested once and not duplicated.

Said another way, you should avoid UI tests and API tests that exercise the same API endpoints in a similar way. API tests are most effective as either standalone tests that are not duplicated in your UI tests, or when combined with a UI test to setup data or verify state after some UI interactions occur.

Using Cypress for API testing

Cypress is a JavaScript testing platform that enables front-end developers and test automation engineers to write automated tests for their web applications. While Cypress is mainly used for end-to-end and component testing, it can be used for API testing as well.

In this article we’ll be focusing a lot on the request() command, which is Cypress’s built-in function for making HTTP requests and will be used heavily in our API tests.

The .request() command

Cypress’s request() command makes an HTTP request to a specified URL and returns a Promise containing the associated HTTP response. The simplest way to call the request() command is to pass a single parameter containing a valid URL:

cy.request("https://www.example.com");

Cypress automatically assumes that this request should use the HTTP GET method, but any HTTP method can be passed explicitly to request(), including GET, POST, PUT, DELETE, and PATCH.

Command chaining is a common pattern in Cypress, and its no surprise that it’s also supported in the request() command. With command chaining, you can do things like make multiple sequential calls or add assertions against the response returned from the request() command like in the example below:

cy.request({
  method: "GET",
  url: "https://www.example.com",
}).then((response) => {
  expect(response.status).to.eq(200);
});

You can find the complete list of parameters supported by the request() command in the Cypress docs.

How to test APIs with Cypress

This section will cover how to install Cypress and use the request() command to make API calls. We will also test various parts of the response data. We will be writing tests against the {JSON} Placeholder site, which exposes a of API endpoints that can be used for testing purposes.

Let’s get started.

Run the command below to start up our new Cypress project. This command will create a package.json file for our project:

npm init -y

Next, run the command below to install Cypress as a dev dependency:

npm install -save-dev Cypress

Add the scripts below to the package.json file:

  "scripts": {
    "cypress: open": "./node_modules/.bin/cypress open",
    "cypress: run": "./node_modules/.bin/cypress run --spec ** / *. spec.js"
  },

With that done, run the command below to start up Cypress:

npm run cypress:open

After the dialog appears, click on the Create new empty spec button. Cypress will generate a new file named spec.cy.js. This is the file we’ll be updating in order to test out the JSON Placeholder API.

In the code example below, I’ve created four tests that demonstrate the different type of assertions you can make against API responses:

describe("a way to test APIs with cypress", () => {
  // Test 1
  it("checks the response code of the request", () => {
    cy.request({
      method: "GET",
      url: "https://jsonplaceholder.typicode.com/albums/1/photos",
    })
      .its("status")
      .should("be.equal", 200);
  });
  // Test 2
  it("checking the headers of the data", () => {
    cy.request({
      method: "GET",
      url: "https://jsonplaceholder.typicode.com/albums/1/photos",
    })
      .its("headers")
      .its("content-type")
      .should("include", "application/json");
  });
  // Test 3
  it("checking that the request returns 50 items", () => {
    cy.request({
      method: "GET",
      // This specific URL returns an array with 50 items
      url: "https://jsonplaceholder.typicode.com/albums/1/photos",
    })
      .its("body")
      .should("have.length", 50);
  });
  // Test 4
  it("should make a Post request", () => {
    cy.request({
      method: "POST",
      url: "https://jsonplaceholder.typicode.com/posts",
      body: JSON.stringify({
        title: "foo",
        body: "bar",
        userId: 1,
      }),
      headers: {
        "Content-type": "application/json; charset=UTF-8",
      },
    })
      .its("status")
      .should("be.equal", 201);
  });
});

As you can see, the code itself is pretty easy to read. The first test block makes a GET request to the JSON Placeholder API and after that, we check its status code and that it should be equal to a status code of 200.

The second test block checks that the content type includes application/json under its header, while the third section checks that the response data returns an array with exactly 50 items.

The fourth test makes a POST request to another URL given to us by the JSON Placeholder API and checking the response status code.

Now, I don’t know about you, but when developing new tests I always add an intentional failure to make sure that the failure path is working. Let’s modify the third test with an intentional failure and see if it fails, as shown in the code block below:

it("checking that the request returns 50 items", () => {
  cy.request({
    method: "GET",
    // This specific URL returns an array with 50 items
    url: "https://jsonplaceholder.typicode.com/albums/1/photos",
  })
    .its("body")
    .should("have.length", 52); // This should be 50
});

When re-running the test in Cypress, you should see a failure displayed with information on the expected condition (52 items returned) and the actual condition (50 items returned).

Conclusion

While tools like Postman and REST Assured are standalone tools for writing API tests, using Cypress for API testing can be a convenient option when used alongside end-to-end tests. In this article we covered some principles around when you should (and shouldn’t) write API tests, and how to write API tests in Cypress via its request() command.

Happy testing!

Get started with Reflect today

Create your first test in 2 minutes, no installation or setup required. Accelerate your testing efforts with fast and maintainable test suites without writing a line of code.

Copyright © 2022 Reflect Software Inc. All Rights Reserved.