API Testing with Cypress: Part 1 - Setup
Tags: tutorial, testing, javascript, node
Published: 2021-05-17 17:26:33

# Hello folks!!

It’s been a long time since I last wrote something here. A few days ago I was thinking about something that might be interesting to share with you about REST APIs automation testing. So the idea came to me:

> Why not use Cypress to create a complete API testing project > from scratch? We can use TDD to create the test, do all the > necessary validations and put this into a CI pipeline! 

**So lets go for it!**

I will split this project into three parts, so that the content does not become too boring.

* **1st part:** we will set up the project and a brief introduction to the integration tests.
* **2nd part:** we will only focus on the tests techniques.
* **3rd part:** we will focus on putting this project in an CI pipeline on **Github Actions**.

## But why should we use Cypress?

Cypress is an user-friendly testing framework, easy to create your automation and no configuration is required to start writing your tests. All the unit testing tools that you are already familiar with are included as well.

With Cypress you can do:
* e2e tests
* unit tests
* component testing
* API testing
* visual regression testing
* and you can even combine them all

# Prerequisites

The first thing we need to do is to setup our environment. So here are some things that you should have to start this project:
* VSCode: https://code.visualstudio.com/download
* Git/Github: https://github.com
* NPM: https://www.npmjs.com/get-npm
* NodeJS: https://nodejs.org/en/download

# Github

First of all, let’s create a repository on github, it will be responsible for storing and handling the versioning of our test code. We should put a repository name, add brief description, a README and a gitignore:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nbgkplvnwe24514hpgpj.png)

After that, we will clone this repository on our local machine. Fisrt, copy your repository address:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86e0dotcc9lb8dr35lw4.png)

Then type in your terminal the git clone command and paste YOUR repository address. In my case, the command will be:

```
git clone https://github.com/murillowelsi/cypress-api-tutorial.git
```

Open the cloned repository in your VSCode and let’s start setting up the project.

# Creating a Cypress project

Now we’ll start a node project (default settings) by using the npm command:

```
npm init -y
```

Then we will install Cypress in the project as a dev dependency:

```
npm i cypress -D
```

Now let’s add the following lines to the package.json file, script section:

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

The package.json will look like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/17p3kvk050g1nu5vsi1g.png)

To start the Cypress project run the command:

```
npm run cypress:open
```

After executing this command, a sample Cypress project structure will be created:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i9gpewmphdx5b3qiez3e.png)

We will not use this samples in this tutorial, so let's remove the entire examples folder:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqvlmo4u50nfha5maxey.png)

```
rm -rf cypress/integration/examples/
```

With the Integration folder clean, let’s move on to the next step.

# Creating our first test

Within Integration we will create a file called `test` with the `spec.js` extension — to be identified and executed as a test spec, and we will start to write our first test.
Mocha offers us the following test organization structure:

```javascript
describe('Mocha’s interface', () => {
  context('it provides a way to keep tests easier to read and organized.', () => {
    it('This is your test case', () => {
      expect(true).to.eq(true)
    });
  });
});
```

A spec has three main building blocks that you can see above. This will make it easier to read the tests:

* `describe()` function is a way to group tests in Mocha.
* `context()` function is another level of grouping tests according to the test context.
* `it()` function is used to put it's title in a human-readable way to describe the test case. 

Let’s save the test.spec.js file and run the command:

```
npm run cypress:run
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/af3b5sj2f849har535c2.png)

We can also force an error to see how it will be displayed in terminal:

```javascript
describe('Mocha’s interface', () => {
  context('it provides a way to keep tests easier to read and organized.', () => {
    it('This is your test case', () => {
      expect(true).to.eq(false)
    });
  });
});
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sbkza2npe0nylhwreszk.png)

# Target API

We will use the Serverest API project as the target of our tests. This API is an awesome project idealized by [Paulo Gonçalves](https://www.linkedin.com/in/paulo-goncalves/), and mantained by the brazilian opensource community, which allows us to test the most used HTTP methods. 

> You can check the documentation in https://serverest.dev/.

Now let’s create a new file called `GETProdutos.spec.js` and make the first call to the target API, using the GET verb in the `/produtos` route, in order to get a list of products.
To make an HTTP request we must use the `cy.request()` function, passing the `method` and `url` parameters:

Syntax:
```
cy.request(method, url)
```

* `method` (String): GET,POST, PUT, DELETE. If no method is defined, Cypress uses the GET method by default.
* `url` (String): The URL to make the request to.

```javascript
/// <reference types="cypress" />

describe('Products api', () => {
    context('GET /produtos', () => {
        it('should return a list with all products', () => {
            cy.request({
                method: 'GET',
                url: 'https://serverest.dev/produtos'
            })
                .should((response) => {
                    cy.log(JSON.stringify(response.body))
                });
        });
    });
});
```

The `.should()` function is modeled identically to the way Promises work in JavaScript. Whatever is returned from the callback function becomes the new subject and will flow into the next command.
Passing a function to `.should()` enables you to make multiple assertions on the yielded subject. For now we will not make any assertions, we will just throw the result on the screen using `cy.log()`.

Let’s run the `cypress:open` command this time to check the results directly in the browser:

```
npm run cypress:open
```

The following window will be displayed. Then click on the test spec that you want to run:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cffu8au2z27m2igbuqcg.png)

Cypress will open the browser, run the tests and show the results on the screen:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4j39wim94a2n3gbyyi1p.png)

Finally, let’s add some assertions inside our it() function, so it becomes a real test.

To validate that the status code we want is actually 200, add the following line:

```javascript
expect(response.status).to.eq(200)
```

Access the products endpoint directly in your browser (https://serverest.dev/produtos) to see what kind of assertions we can make in the response body.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ha18frxt12zm60b5f769.png)

We also can say that we expect that the ‘quantidade’ key should always be 2, since the registered data is removed daily in the ServeRest project. So the size of the produtos array will also be 2.

Add these two validations:

```javascript
expect(response.body.quantidade).to.eq(2)
expect(response.body.produtos.length).to.be.eq(2);
```

And as a last validation, we can also say that the objects within the product array must contain the keys ‘name’, ‘price’, ‘description’, ‘quantity’, ‘_id’.

```javascript
expect(response.body.produtos[0]).to.have.all.keys(
  'nome', 'preco', 'descricao', 'quantidade', '_id'
)
```

Our test will look like this:

```javascript
/// <reference types="cypress" />

describe('Products api', () => {
    context('GET /produtos', () => {
        it('should return a list with all products', () => {
            cy.request({
                method: 'GET',
                url: 'https://serverest.dev/produtos'
            })
                .should((response) => {
                    expect(response.status).to.eq(200)
                    expect(response.body.quantidade).to.eq(2)
                    expect(response.body.produtos.length).to.be.eq(2);
                    expect(response.body.produtos[0]).to.have.all.keys(
                      'nome', 'preco', 'descricao', 'quantidade', '_id'
                    )
                });
        });
    });
});
```

If we run the tests again, we will see that all assertions are passing successfully.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1lqist5ll1d2yhc9kjg.png)

**Success! We wrote our first API tests using Cypress.**

We should not forget to send our code to Github, after all we want to save and version the project.

> The purpose of this article is not to show you how to use git but let’s see some commands that can help you push your code to Github.

Let’s add some things to our `.gitignore` file that we don’t want to send to the remote repository:

```bash
# Dependency directories
node_modules/
videos/
screenshots/
package-lock.json
```

Run the command `git add` to add all files to the staging area on the terminal.

```bash
git add .
```

Use git status to display the list of changed files to be committed.

```bash
git status
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gh7vgronrokeu8iz7o6.png)

Then run the `git commit` that will create a snapshot of the changes and save it to the git directory. We use the `-m` parameter to add a message to the commit, describing what was changed.

```
git commit -m "First cypress project commit"
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j0xvob3qhk32eyomfgpn.png)

Finally we are going to push the changes from our local repository to the remote repository using `git push`.

```
git push origin main
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/filzz0ob7w4yftyvcye5.png)

If we check our repository on Github, we will see all the changes we’ve made in the main branch:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ru0yqfua9ghg2142r73o.png)

This is the link to my github repository, just in case you want to take a look:

https://github.com/murillowelsi/cypress-api-tutorial

So we’ve just finished the first part of this series of articles that I want to share with you guys. In the next one, we will refactor this test project to make it more reliable and robust.

**See ya next time!**

> So, what do you think? Do you do anything differently when creating your projects?

Leave your comment! Thanks!