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:
After that, we will clone this repository on our local machine. Fisrt, copy your repository address:
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:
"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:
To start the Cypress project run the command:
npm run cypress:open
After executing this command, a sample Cypress project structure will be created:
We will not use this samples in this tutorial, so let's remove the entire examples folder:
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:
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
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)
});
});
});
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)
-
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))
});
});
});
});
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:
Cypress will open the browser, run the tests and show the results on the screen:
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)
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.
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);
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'
)
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'
)
});
});
});
});
If we run the tests again, we will see that all assertions are passing successfully.
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
Run the command git add
to add all files to the staging area on the terminal.
git add .
Use git status to display the list of changed files to be committed.
git status
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"
Finally we are going to push the changes from our local repository to the remote repository using git push
.
git push origin main
If we check our repository on Github, we will see all the changes we’ve made in the main branch:
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!
Top comments (5)
This is exactly what I was looking for. Its very well explained and a great article for any starter.
Thank you :)
When would you push the part 3??
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?
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!
Good article and described well.
Thank you so much, Pradeep. I'll post the other two articles as soon as possible!