DEV Community

Cover image for API Testing with Cypress
Dennis Whalen for Leading EDJE

Posted on • Edited on • Originally published at dennis-whalen.com

API Testing with Cypress

In this post we'll talk about using Cypress to run API tests. But what is Cypress?

Cypress is an open sourced JavaScript-based test automation framework that is typically used for testing web applications that leverage modern JavaScript frameworks.

If you're just getting started with Cypress, you might want to check out my previous post to get a general understanding of Cypress and how to get it running in your environment. In that post I covered how to install Cypress locally and get some UI tests running. In this article I am going to continue adding to that project for the API testing.

Setting up JSON-Server

Before we we can test API endpoints, we need some API endpoints to test. For that I am going to quickly setup some endpoints on my machine that I can test using JSON Server.

JSON Server is an open-sourced Node module you can use to quickly setup test endpoints for mocking and testing.

Add dependencies for json-server and faker

To get our endpoint running locally we need to add json-server and faker to our package.json file. Faker will be used to generate some random data. Update your dev-dependencies section to look something like this:

"devDependencies": {
    "cypress": "^6.9.1",
    "faker": "^4.1.0",
    "json-server": "^0.15.0"
  }
Enter fullscreen mode Exit fullscreen mode

Run npm install to load install the newly added modules.

Add a process to load data into our endpoint

JSON Server needs some data to serve through our endpoint. To make that happen, create a file named employees.js and paste the following into it:

var faker = require('faker')
function generateEmployees () {
  var employees = []
  for (var id = 0; id < 50; id++) {
    var firstName = faker.name.firstName()
    var lastName = faker.name.lastName()
    var email = faker.internet.email()
    employees.push({
      "id": id,
      "first_name": firstName,
      "last_name": lastName,
      "email": email
    })
  }
  return { "employees": employees }
}
module.exports = generateEmployees
Enter fullscreen mode Exit fullscreen mode

This function will just return an array of 50 employees with random names and emails.

Start json-server

From that command line run json-server employees.js. This will start json-server and the endpoint will return the randomly generated employees. If things go as expected, you should see something like this:
Alt Text

In addition to providing an endpoint to retrieve your data, JSON Server allows you to make POST, PUT, PATCH or DELETE requests, making it an ideal solution for mocking endpoints.

With JSON Server you can start building test for API endpoints before the developer implements the endpoint. You can easily mock the expected responses and once the API is implemented, your tests can point to that implementation instead of JSON Server. Development and API test automation can happen in parallel.

Now let's create some tests!

Your first API tests

To get started we're going to create a test that performs a GET request to our /employees endpoint and verifies the response is JSON, the status code is 200, and the response contains 50 employees.

Create file named employeeTests.js with the following content:

describe('employees API', () => {
  it('verify request returns JSON', () => {
    cy.request('http://localhost:3000/employees').its('headers').its('content-type').should('include', 'application/json')
  })

  it('verify the request returns the correct status code', () => {
    cy.request('http://localhost:3000/employees').its('status').should('be.equal', 200)
  })

  it('verify the request returns 50 items', () => {
    cy.request('http://localhost:3000/employees').its('body').should('have.length', 50)
  })
})
Enter fullscreen mode Exit fullscreen mode

There are 3 tests here that will do our preliminary validation. Lets run the tests!

Start the test runner

You can start the test runner with the command: ./node_modules/.bin/cypress open

If you need help with this, refer back to my previous post to get you started.

Run the tests

Once the Cypress Runner starts you should see your employeeTests.js file. Be sure you've started json-server and then run the test by clicking the file in the Cypress Test Runner. In no time you will see your results:
Alt Text

Make sure your test fails

I usually don't trust my tests until I see them fail. I am going to edit the employeeTests.js file to change the expected status code to 201 just so I can be sure these tests are working. Rerun the test and you should see something like this:
image

A couple things of note here:

  • the Test Runner allows me to rerun tests without reloading the runner, and it is immediately aware of any changes I make to the tests.
  • if you expand the failed test you can get some more useful info about the failure: Alt Text

More API tests

So now we have a test that verifies we can get our list of employees. Let's create a test that verifies we can add and delete an employee.

Create file named addDeleteEmployeeTest.js with the following content:

let newId;

describe('employees API', () => {

  it('Add a new item', () => {   
    cy.request('POST', 'http://localhost:3000/employees',{ first_name: 'New', last_name: 'Dude', email: "new_dude@googling.com" })
    .its('body').then((body) => {
      newId = body.id;
    })
  })

  it('Verify the new item exists exists', () => {
    cy.request('http://localhost:3000/employees/' + newId).then((response) => {
      expect(response.status).to.eq(200)
      expect(response.body).to.have.property('first_name', 'New') 
      expect(response.body).to.have.property('last_name', 'Dude') 
      expect(response.body).to.have.property('email', 'new_dude@googling.com') 
    })
  })

  it('Delete the newly added item', () => {
    cy.request('DELETE', 'http://localhost:3000/employees/' + newId).then((response) => {
      expect(response.status).to.eq(200)
    })
  })

  it('Verify the item was deleted', () => {
    cy.request({url: 'http://localhost:3000/employees/' + newId, failOnStatusCode: false}).then((response) => {
      expect(response.status).to.eq(404)
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

Hopefully these tests are pretty self explanatory. With these new tests we are validating we can add and delete a new employee. Go ahead and run addDeleteEmployeeTest.js from the Cypress runner. You should see something like this:
Alt Text

These results show we are able to add and delete a new employee via our API endpoint.

Running a test from the command line

As mentioned in my previous post, we ultimately we want these tests to run in a CI pipeline, which means we need to be able to run them from the command line. Running from the command line is easy enough:

./node_modules/.bin/cypress run --spec cypress/integration/examples/addDeleteEmployeeTest.js
Enter fullscreen mode Exit fullscreen mode

You should see something like this:
Alt Text

What's Next?

In my first 2 posts I've shown you how to get Cypress running locally and get some UI and API test running. I feel like we've covered a lot, but we've really only scratched the surface. The Cypress site has a lot more detailed documentation and examples of the power of Cypress.

In future posts I want to look into what we need to do to move these tests from our local environment into a CI pipeline, and I also want to look at some reporting options.

If there are any questions, or ideas for future posts, please let me know in the comments.

Until then, stay tuned!


Smart EDJE Image

Top comments (3)

Collapse
 
bahmutov profile image
Gleb Bahmutov

Great stuff, and you can reflect the requests and API responses back automatically, see the github.com/bahmutov/cy-api that builds on top of cy.request

Collapse
 
ash2k87 profile image
ash2k87

Nice post. Could you please cover on the limitations of cypress like multiple windows/tabs handling , SSO sign-handling in UI testing and what alternative options are provided in cypress to address these.

Collapse
 
dwwhalen profile image
Dennis Whalen

Sure, I'll add that to my list for future posts. Thanks!