REST API test automation with PactumJS

PactumJS logo

‎‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎Recently I needed an API test automation tool for a REST API that I’m writing as a part of my side project. My requirements were the following: I wanted to have coded tests that will be a part of the same repo as an API code, and I wanted a Javascript-based solution since the API was based on NodeJS/Express. After a brief investigation of currently popular and active API test automation tools, one particular solution has drawn my attention – PactumJS. PactumJS is a feature-rich REST API test automation tool suitable for component, contract & E2E testing. Since it seemed like a simple but powerful and feature-rich tool, I decided to give it a try.

Installation and setup

Pactum can be installed via npm or yarn:

# npm
npm install --save-dev pactum

# yarn
yarn add pactum

Since PactumJS acts as a REST API client without an embedded test framework, one needs to be added to the project manually. For this demonstration, let’s install and use Mocha:

# npm
npm install --save-dev mocha

# yarn
yarn add mocha

Afterward, we can run our PactumJS tests by running the npm test command.

If you want to see and try some real examples, I created a repository with test samples which can be found here: https://github.com/azeljkovic/test-automation-bucket-part2-examples/tree/main/API/PactumJS-Mocha-RestfulBooker. In the readme file you can find a link to an API under test as well as install/run instructions.

PactumJS in action

Let’s start with a simple test example:

it('Update booking - valid', async () => {
    await pactum.spec()
        .put(endpoints.booking + 5)
        .withAuth(authData.validUsername, authData.validPassword)
        .withHeaders('Accept', 'application/json')
        .withBody(requestJSON)
        .expectStatus(200)
        .expectHeaderContains('content-type', 'application/json')
        .expectJson(requestJSON);
});

At first sight, we can notice that tests are readable and easy to understand. pactum.spec() method with the request method (which takes the URL as a parameter) is the foundation of every API test. GET, POST, PUT, PATCH, and DELETE are supported request methods, and if you want to use something more exotic, you can use .withMethod() with your HTTP verb as a parameter followed by the .withPath() method with the URL parameter. After this is defined we can further add parameters, headers, cookies, body, files, etc. in order to define the request.

In the example above we are performing a PUT request, authenticating with the username/password, and sending necessary headers and body. After the response is received, the test is checking if the status code is 200, the content type is application/json, and if the response body is equal to a previously defined JSON file. Other things that you can validate after the request is made are errors, headers, cookies, response time, and different types of response body/JSON validations.

Additional capabilities

PactumJS supports several additional concepts of API testing:

  • integration API testing – integration between two or more APIs can be tested due to a possibility to call multiple requests within a single test, use them together and share data between them
  • component API testing – API can be tested in isolation by mocking the external dependencies. PactumJS can help with this by providing a flexible integrated mock server out of the box. Example mock server would look like this:
const { mock } = require('pactum');

mock.addInteraction({
  request: {
    method: 'GET',
    path: '/endpoint'
  },
  response: {
    status: 404,
    body: 'Nothing here...'
  }
});

mock.start(); //default port is 9393, you can set the custom one as a parameter
  • contract testing – testing an API contract between consumer and producer. (this feature is marked as experimental in the documentation, which probably means that its faith is still quite unknown)
  • ability to make GraphQL requests
  • fuzz testing and advanced matching capabilities
  • data templates and references – mechanisms for defining flexible and reusable data that can be used across multiple tests

Conclusion

During my trial with PactumJS, I have not used all of the advanced features that are offered, but the list of them is quite impressive for an API testing tool. The functionalities that I used were straightforward and intuitive, so an average user will be able to start with the PactumJS test very fast thanks to its gentle learning curve and simplicity. The only two things that I struggled with while working with PactumJS are:

  1. Documentation structure – it is not easy to navigate through documentation since all pages can be accessed only via one page – https://pactumjs.github.io/#/pactum or from the top right hover menu, which is not very obvious at first.
  2. Community support – there are not many real-world examples and solutions on the internet since the community is (still) not very large, so if you get stuck, you’re on your own… However, this problem will fade away when (if?) the popularity of PactumJS grows.

All in all, PactumJS is a feature-rich tool that managed to keep the simplicity and ease of use. If its maintainers keep doing a good job improving the current code, I believe that a wider community will recognize the value of the tool, which will be the right combination to enable the success of the PactumJS.

Useful links

Examples:

https://github.com/azeljkovic/test-automation-bucket-part2-examples/tree/main/API/PactumJS-Mocha-RestfulBooker

PactumJS:

https://pactumjs.github.io/#/

https://github.com/pactumjs/pactum

2 thoughts on “REST API test automation with PactumJS

  1. How to set multiple header elements,

    “Content-Type”, “application/json”,
    “X-Client-Id”, “MyTestApp”,
    “X-Message-Created-Ts”, “2022-JUN-06 20:06”,
    “X-Message-Id”, “4e8fb14c-c71f-46f8-b41a-561d393037ce”,
    “X-Transaction-Created-Ts”, “2022-JUN-06 20:06”,
    “X-Transaction-Id”, “f11c97dc-a6eb-4ff7-aff6-de47c4686941”

    I tried with
    .withHeaders(“Content-Type”, “application/json”, “X-Client-Id”, “MyTestApp”, “X-Message-Created-Ts”, “2022-JUN-06 20:06″,”X-Message-Id”, “4e8fb14c-c71f-46f8-b41a-561d393037ce”, “X-Transaction-Created-Ts”, “2022-JUN-06 20:06”, “X-Transaction-Id”, “f11c97dc-a6eb-4ff7-aff6-de47c4686941”)

    And I am getting
    “invalid-param”: [
    {
    “name”: “X-Transaction-Id”,
    “reason”: “Global Transaction Id is missing in Header”
    },
    {
    “name”: “X-Message-Id”,
    “reason”: “Message Id is missing in Header”
    },
    {
    “name”: “X-Transaction-Created-Ts”,
    “reason”: “Transaction created date is missing in Header”
    },
    {
    “name”: “X-Transaction-Created-Ts”,
    “reason”: “Supplied transaction created date is in wrong format in Header”
    },
    {
    “name”: “X-Message-Created-Ts”,
    “reason”: “Message created date is missing in Header”
    },
    {
    “name”: “X-Message-Created-Ts”,
    “reason”: “Supplied message created date is in wrong format in Header”
    }
    ],

  2. You need to send them as an object. (https://pactumjs.github.io/api/requests/withHeaders.html#multiple-headers)
    Something like:

    .withHeaders({
    “Content-Type”: “application/json”,
    “X-Client-Id”: “MyTestApp”,
    “X-Message-Created-Ts”: “2022-JUN-06 20:06″,
    ”X-Message-Id”: “4e8fb14c-c71f-46f8-b41a-561d393037ce”,
    “X-Transaction-Created-Ts”: “2022-JUN-06 20:06”,
    “X-Transaction-Id”: “f11c97dc-a6eb-4ff7-aff6-de47c4686941”
    })

Leave a Reply

Your email address will not be published.