DEV Community

loading...
Cover image for API Testing with Cypress: Part 1 - Setup

API Testing with Cypress: Part 1 - Setup

Murillo Welsi de Souza Pereira
I’m a QA Engineer with five years experience in software testing. Certified Tester - ISTQB - CTFL.
Updated on ・7 min read

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:

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

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

Alt Text

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

npm i cypress -D
Enter fullscreen mode Exit fullscreen mode

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

"scripts": {
     "cypress: open": "./node_modules/.bin/cypress open",
     "cypress: run": "./node_modules/.bin/cypress run --spec ** / *. spec.js"
Enter fullscreen mode Exit fullscreen mode

The package.json will look like this:

Alt Text

To start the Cypress project run the command:

npm run cypress:open
Enter fullscreen mode Exit fullscreen mode

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

Alt Text

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

Alt Text

rm -rf cypress/integration/examples/
Enter fullscreen mode Exit fullscreen mode

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:

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)
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Alt Text

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

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)
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

Alt Text

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, 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)
Enter fullscreen mode Exit fullscreen mode
  • 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.
/// <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))
                });
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Alt Text

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

Alt Text

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:

expect(response.status).to.eq(200)
Enter fullscreen mode Exit fullscreen mode

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

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:

expect(response.body.quantidade).to.eq(2)
expect(response.body.produtos.length).to.be.eq(2);
Enter fullscreen mode Exit fullscreen mode

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’.

expect(response.body.produtos[0]).to.have.all.keys(
  'nome', 'preco', 'descricao', 'quantidade', '_id'
)
Enter fullscreen mode Exit fullscreen mode

Our test will look like this:

/// <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'
                    )
                });
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

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

Alt Text

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:

# Dependency directories
node_modules/
videos/
screenshots/
package-lock.json
Enter fullscreen mode Exit fullscreen mode

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

git add .
Enter fullscreen mode Exit fullscreen mode

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

git status
Enter fullscreen mode Exit fullscreen mode

Alt Text

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"
Enter fullscreen mode Exit fullscreen mode

Alt Text

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

git push origin main
Enter fullscreen mode Exit fullscreen mode

Alt Text

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

Alt Text

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!

Discussion (4)

Collapse
thiagojacinto profile image
Thiago Jacinto

Congrats, Murillo. Looking forward to the next chapters!

I just want to add that I saw the opportunity of using something like a JSON schema validator instead of the last expect that validates all fields of object. What do you think about that?

Collapse
murillowelsi profile image
Murillo Welsi de Souza Pereira Author

In fact this is a great idea, it would work perfectly for this scenario. Perhaps in a scenario where there are business rules, where the fields dynamically change payload it would easier to do this validation of the keys as I did.

I will try to add a contract test as you suggested in the next one.

Thanks for you suggestion, Thiago!

Collapse
pradeepku123 profile image
Pradeep Kumar Behera

Good article and described well.

Collapse
murillowelsi profile image
Murillo Welsi de Souza Pereira Author

Thank you so much, Pradeep. I'll post the other two articles as soon as possible!