API Testing with Cypress
Tags: testing, automation, codequality, tutorial
Published: 2021-04-25 15:40:27

In this post we'll talk about using [Cypress](https://www.cypress.io/) 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](https://dev.to/leading-edje/kickstart-your-ui-and-api-testing-with-cypress-4ln3) 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](https://github.com/typicode/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:
```js
"devDependencies": {
    "cypress": "^6.9.1",
    "faker": "^4.1.0",
    "json-server": "^0.15.0"
  }
```
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:
```js
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
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ost2p98clcjck4a3733q.png)

* You should now have a API endpoint at [http://localhost:3000/employees](http://localhost:3000/employees), and can view that data in your browser:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8jyacgxq7y9boakjmbcp.png)


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:
```js
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)
  })
})
```
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](https://dev.to/leading-edje/kickstart-your-ui-and-api-testing-with-cypress-4ln3) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oektnlydi7f6wuty5owl.png)

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64z7azd2tpr8d2iyv3ma.png)
 
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7yhnagn7z5bsqr1tm4t.png)

# 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:
```js
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)
    })
  })
})
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aybz8xgkbu7g76zi9a2i.png)

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](https://dev.to/leading-edje/kickstart-your-ui-and-api-testing-with-cypress-4ln3), 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
```
You should see something like this:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rtascjbtszbyqod88stc.png)

# 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](https://docs.cypress.io/guides/overview/why-cypress) and [examples](https://example.cypress.io/) 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!

<a href="https://dev.to/leading-edje">
  ![Smart EDJE Image](https://dev-to-uploads.s3.amazonaws.com/i/5uo60qforg9yqdpgzncq.png)
<a/>