API Testing using SuperTest Mocha ChaiJS and FakerJS

API Testing using SuperTest Mocha ChaiJS and FakerJS

I have been using JavaScript for UI automation and am in love with it for many reasons, but one of the reasons that always helps me is when I Google any library/package with just npm word, there are many solutions available, which makes life so much easier. The other benefit is saving time as well.

It is possible to automate API tests using several tools available on the market. It is up to you to choose which tool is most appropriate for your needs.

The first thing I did was to explore and try to find some library/package on npm which I could use to test APIs. In the end, I found SuperTest to be the answer to my search. Using this tool may be the best solution for scaling your automation framework with additional capabilities. It’s easy to use and allows you to easily integrate it into existing automation frameworks.

In this article, we will be using [SuperTest](npmjs.com/package/supertest "npmjs.com/package/supertest"), [Mocha](mochajs.org "mochajs.org"), and [Chai](chaijs.com "chaijs.com"). We will use [FakerJS](fakerjs.dev "fakerjs.dev") to generate the test data and JavaScript for scripting. Let’s look into them one by one.

SuperTest

SuperTest module is to provide a high-level abstraction for testing HTTP, while still allowing you to drop down to the [lower-level API](ladjs.github.io/superagent "ladjs.github.io/superagent") provided by superagent.

Mocha

Mocha is a feature-rich JavaScript test framework running on [Node.js](nodejs.org "nodejs.org") and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

Chai

Chai is a BDD / TDD assertion library for [node](nodejs.org "nodejs.org") and the browser that can be delightfully paired with any javascript testing framework.

Faker

Generate massive amounts of fake (but realistic) data for testing and development.

Getting Started

Step 1) To start with you need to have [Node.js](nodejs.org "nodejs.org") installed on your machine. You can download it directly from the Node.js [website](nodejs.org/en "nodejs.org/en") and install it on your machine if you are not already using it.

Once installed check the version

node -v

Step 2) [Install Visual Studio Code](codewithmmak.com/blog/install-visual-studio.. "codewithmmak.com/blog/install-visual-studio..") (this will help you write formatted code but you can pick any text editor of your choice)

Step 3) Open Visual Studio Code

Step 4) Open your integrated Terminal and run the following command

mkdir supertest-mocha-chai-javascript

Step 5) Open the directory

cd supertest-mocha-chai-javascript

Step 6) Create a new package.json file

npm init -y

Your package.json file should be like this:

{
"name": "supertest-mocha-chai-javascript",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

Step 7) I will be using [Mocha](mochajs.org "mochajs.org") JavaScript test framework for writing the API tests, [ChaiJS](chaijs.com "chaijs.com") for assertions, and [mochawesome](npmjs.com/package/mochawesome "npmjs.com/package/mochawesome") to generate HTML reports. Also, I will use [Faker](fakerjs.dev "fakerjs.dev"), one of the powerful packages to generate test dummy data. Install all the required packages

npm install --save-dev supertest mocha chai mochawesome @faker-js/faker

Once the installation is complete node_module will be created with all the dependencies installed in it.

Your package.json file should look like this:

{
"name": "supertest-mocha-chai-javascript",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"supertest",
"mocha",
"chai",
"mochawesome"
],
"author": "Code with MMAK",
"license": "ISC",
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"chai": "^4.3.7",
"mocha": "^10.1.0",
"mochawesome": "^7.1.3",
"supertest": "^6.3.1"
}
}

Step 8) Create a .gitignore file so that unwanted files are not committed to the repository

node_modules/
mochawesome-report/
test-results/
downloads/*
log/*

Now you can start writing your API tests.

Following is the list of APIs on the Reqres — A hosted REST-API ready to respond to your AJAX requests website which I have used to write end-to-end tests.

  1. Create a user
  2. Get the user details
  3. Updated user details
  4. Update the user with partial details
  5. Delete user

For the end-to-end automation testing strategy, I have followed the steps given below:

  1. Create a user with when the date is supplied from the JSON file. Also as the real-time approach, I have used the Fakerjs npm package which will give you dummy test data, which looks real.
  2. Assert the response by either comparing it with JSON data or by matching it with data stored in the variable.
  3. Get the user details by query param, without query param and path param. And assert the response for each.
  4. Updated user full details and assert the response
  5. Update user practical details and assert the response.
  6. Finally, delete the user and assert the response.

It’s time to code !!

Base Setup

To being with we will start implementing the base so that it can be reused and we are not going to write unnecessary repeated code.

Create a folder and name it config inside this folder create a JSON file named reqres.config.json file. here we will keep our base URL, which is the test URL

{
"baseUrl": "reqres.in"
}

POST Request

To being with create a folder and name it test-reqres-api and then create a test file named postTest.js.

We are going to create a post request by using data stored in JSON, with this we will be able to create a user.

Create a folder named test-data and then create a JSON file named user-data.json

{
"name": "Code with MMAK",
"job": "Testing"
}

Now start writing a line of code to import the supertest library and expect the library from chai.

const request = require('supertest');
const expect = require('chai').expect;
const reqres = require('../config/reqres.config.json');
const userData = require('../test-data/user-data.json');

describe('POST API tests using SuperTest', () => {

it('should successfully pass the test for POST api when test data from json file is used', (done) => {  
    request(reqres.baseUrl)  
        .post('/api/users')  
        .send(userData)  
        .set('Accept', 'application/json')  
        .set('Content-Type', 'application/json')  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(201);  
            expect(res.body.name).to.be.equal('Code with MMAK');  
            expect(res.body.job).to.be.equal('Testing');  
            expect(res.body.id).not.to.be.null;  
            expect(res.body.createdAt).not.to.be.null;  
            done();  
        });  
});  

});

Here ‘describe’ means test scenario and ‘it’ means individual test cases

post — is the request type

send — is to send the data with the post request

set — is to set the header of the request

end — is to say the request is ended and we will perform the assertion

expect — is to validate the response

done — is to say our request is completed and the test is done.

Let’s run the test:

mocha ./test-reqres-api --reporter spec --reporter mochawesome --timeout 5000

Dummy data using fakerjs

const request = require('supertest');
const expect = require('chai').expect;
const { faker } = require('@faker-js/faker');
const reqres = require('../config/reqres.config.json');

const randomName = faker.name.findName();
const randomJob = faker.name.jobTitle();

describe('POST API tests using SuperTest', () => {

it('should successfully pass the test for POST api when fakerjs dummy data is used', (done) => {  
    request(reqres.baseUrl)  
        .post('/api/users')  
        .send({  
            "name": randomName,  
            "job": randomJob  
        })  
        .set('Accept', 'application/json')  
        .set('Content-Type', 'application/json')  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(201);  
            expect(res.body.name).to.be.equal(randomName);  
            expect(res.body.job).to.be.equal(randomJob);  
            expect(res.body.id).not.to.be.null;  
            expect(res.body.createdAt).not.to.be.null;  
            done();  
        });  
});  

});

GET Request

Create a file named getTest.js and write the following code:

const request = require('supertest');
const expect = require('chai').expect;
const reqres = require('../config/reqres.config.json');

describe('GET API tests using SuperTest', () => {

it('should successfully pass the test for get api without query param', (done) => {  
    request(reqres.baseUrl)  
        .get('/api/users/2')  
        // .set('Accept', 'application/json')  
        // .set('Content-Type', 'application/json')  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(200);  
            expect(res.body.data.id).to.be.equal(2);  
            expect(res.body.data.first\_name).to.be.equal('Janet');  
            done();  
        });  
});  
it('should successfully pass the test for get api with query param', (done) => {  
    request(reqres.baseUrl)  
        .get('/api/users')  
        .query({ page: '2' })  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(200);  
            expect(res.body.page).to.be.equal(2);  
            expect(res.body.data\[0\].id).to.be.equal(7);  
            expect(res.body.data\[0\].first\_name).to.be.equal('Michael');  
            done();  
        });  
});  

});

PUT Request

Create a file named putTest.js and write the following code:

const request = require('supertest');
const expect = require('chai').expect;
const reqres = require('../config/reqres.config.json');

describe('PUT API tests using SuperTest', () => {

it('should successfully pass the test for post api', (done) => {  
    request(reqres.baseUrl)  
        .put('/api/users/2')  
        .send({ name: 'Andy', job: 'Admin' })  
        .set('Accept', 'application/json')  
        .set('Content-Type', 'application/json')  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(200);  
            expect(res.body.name).to.be.equal('Andy');  
            expect(res.body.job).to.be.equal('Admin');  
            expect(res.body.updatedAt).not.to.be.null;  
            done();  
        });  
});  

});

PATCH Request

Create a file named patchTest.js and write the following code:

const request = require('supertest');
const expect = require('chai').expect;
const reqres = require('../config/reqres.config.json');

describe('PATCH API tests using SuperTest', () => {

it('should successfully pass the test for patch request', (done) => {  
    request(reqres.baseUrl)  
        .patch('/api/users/2')  
        .send({ name: 'Mike', job: 'Test Lead' })  
        .set('Accept', 'application/json')  
        .set('Content-Type', 'application/json')  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(200);  
            expect(res.body.name).to.be.equal('Mike');  
            expect(res.body.job).to.be.equal('Test Lead');  
            expect(res.body.updatedAt).not.to.be.null;  
            done();  
        });  
});  

});

DELETE Request

Create a file named deleteTest.js and write the following code:

const request = require('supertest');
const expect = require('chai').expect;
const reqres = require('../config/reqres.config.json');

describe('DELETE API tests using SuperTest', () => {

it('should successfully pass the test for delete request', (done) => {  
    request(reqres.baseUrl)  
        .delete('/api/users/2')  
        .set('Accept', 'application/json')  
        .set('Content-Type', 'application/json')  
        .end(function (err, res) {  
            expect(res.statusCode).to.be.equal(204);  
            done();  
        });  
});  

});

Some Tips

  1. If you want to run a single test then use ‘it.only’. Similarly, if you want to run a single test scenario then use ‘describe.only’.
  2. If you want to skip any test in a test suite then use ‘it.skip’. Similarly, if you want to skip the test scenario then use ‘describe.skip.

Code Repository

The sample framework is hosted on GitHub.

Have a suggestion or found a bug? Fork this project to help make this even better.

Star the repo and follow me to get the latest updates

What Do You Think?

Did this work for you?

Could I have done something better?

Have I missed something?

Please share your thoughts and let me know if there are particular things that you would enjoy reading further.

Cheers!