Thanks! We'll be in touch in the next 12 hours
Oops! Something went wrong while submitting the form.

Building A Scalable API Testing Framework With Jest And SuperTest

Focus on API testing

Before starting off, below listed are the reasons why API testing should be encouraged:

  • Identifies bugs before it goes to UI
  • Effective testing at a lower level over high-level broad-stack testing
  • Reduces future efforts to fix defects
  • Time-saving

Well, QA practices are becoming more automation-centric with evolving requirements, but identifying the appropriate approach is the primary and the most essential step. This implies choosing a framework or a tool to develop a test setup which should be:

  • Scalable 
  • Modular
  • Maintainable
  • Able to provide maximum test coverage
  • Extensible
  • Able to generate test reports
  • Easy to integrate with source control tool and CI pipeline

To attain the goal, why not develop your own asset rather than relying on the ready-made tools like Postman, JMeter, or any? Let’s have a look at why you should choose ‘writing your own code’ over depending on the API testing tools available in the market:

  1. Customizable
  2. Saves you from the trap of limitations of a ready-made tool
  3. Freedom to add configurations and libraries as required and not really depend on the specific supported plugins of the tool
  4. No limit on the usage and no question of cost
  5. Let’s take Postman for example. If we are going with Newman (CLI of Postman), there are several efforts that are likely to evolve with growing or changing requirements. Adding a new test requires editing in Postman, saving it in the collection, exporting it again and running the entire collection.json through Newman. Isn’t it tedious to repeat the same process every time?

We can overcome such annoyance and meet our purpose using a self-built Jest framework using SuperTest. Come on, let’s dive in!

Jest and SuperTest

Source: school.geekwall

Why Jest?

Jest is pretty impressive. 

  • High performance
  • Easy and minimal setup
  • Provides in-built assertion library and mocking support
  • Several in-built testing features without any additional configuration
  • Snapshot testing
  • Brilliant test coverage
  • Allows interactive watch mode ( jest --watch or jest --watchAll )

Hold on. Before moving forward, let’s quickly visit Jest configurations, Jest CLI commands, Jest Globals and Javascript async/await for better understanding of the coming content.

Ready, set, go!

Creating a node project jest-supertest in our local and doing npm init. Into the workspace, we will install Jest, jest-stare for generating custom test reports, jest-serial-runner to disable parallel execution (since our tests might be dependent) and save these as dependencies.

CODE: https://gist.github.com/velotiotech/9d75ac0e8fbf22315692be1b995a6687.js

Tags to the scripts block in our package.json. 

CODE: https://gist.github.com/velotiotech/950657f7a9b36949ba94ce82a576c279.js

npm run test command will invoke the test parameter with the following:

  • NODE_TLS_REJECT_UNAUTHORIZED=0: ignores the SSL certificate
  • jest: runs the framework with the configurations defined under Jest block
  • --reporters: default jest-stare 
  • --coverage: invokes test coverage
  • --detectOpenHandles: for debugging
  • --runInBand: serial execution of Jest tests
  • --forceExit: to shut down cleanly
  • --testTimeout = 60000 (custom timeout, default is 5000 milliseconds)

Jest configurations:

[Note: This is customizable as per requirements]

CODE: https://gist.github.com/velotiotech/b284845dff303958c51da4ff7576dacb.js

testSequencer: to invoke testSequencer.js in the workspace to customize the order of running our test files

CODE: https://gist.github.com/velotiotech/06ff38454253bc3bb507869187c737e1.js

Below code in testSequencer.js will run our test files in alphabetical order.

CODE: https://gist.github.com/velotiotech/c57a65bb5856873fa95c29d6ef180755.js

  • verbose: to display individual test results
  • coverageDirectory: creates a custom directory for coverage reports
  • coverageReporters: format of reports generated
  • coverageThreshold: minimum and maximum threshold enforcements for coverage results

Testing endpoints with SuperTest

SuperTest is a node library, superagent driven, to extensively test Restful web services. It hits the HTTP server to send requests (GET, POST, PATCH, PUT, DELETE ) and fetch responses.

Install SuperTest and save it as a dependency.

CODE: https://gist.github.com/velotiotech/2687999b0c6ec956c4dc95a438629cf8.js

CODE: https://gist.github.com/velotiotech/fb2fcdd1c72fa6040cc632b22723b6e0.js

All the required dependencies are installed and our package.json looks like:

CODE: https://gist.github.com/velotiotech/0598f0540b5f7d00a6e9fb7d21bcfbca.js

Now we are ready to create our Jest tests with some defined conventions:

  • describe block - assembles multiple tests or its
  • test block - (an alias usually used is ‘it’) holds single test 
  • expect() -  performs assertions 

It recognizes the test files in __test__/ folder

  • with .test.js extension
  • with .spec.js extension

Here is a reference app for API tests.

Let’s write commonTests.js which will be required by every test file. This hits the app through SuperTest, logs in (if required) and saves authorization token. The aliases are exported from here to be used in all the tests. 

[Note: commonTests.js, be created or not, will vary as per the test requirements]

CODE: https://gist.github.com/velotiotech/5a1e052c2e43b5a2d897823cd696d52c.js

CODE: https://gist.github.com/velotiotech/c313836ffc1c85033d86efce556a9f70.js

Moving forward to writing our tests on POST, GET, PUT and DELETE requests for the basic understanding of the setup. For that, we are creating two test files to also see and understand if the sequencer works.

CODE: https://gist.github.com/velotiotech/6ffe15a635dbc4e3ae0d2ca5d12ff39c.js

As mentioned above and sticking to Jest protocols, we have our tests written.

postAndGet.test.js test file:

  • requires commonTests.js into ‘request’ alias
  • POST requests to api/users endpoint, calls supertest.post() 
  • GET requests to api/users endpoint, calls supertest.get()
  • uses file system to write globals and read those across all the tests
  • validates response returned on hitting the HTTP endpoints

CODE: https://gist.github.com/velotiotech/5b8ea7e5a000c5d893a8175f9e783c44.js

putAndDelete.test.js file:

  • requires commonsTests into ‘request’ alias
  • calls data.json into ‘data’ alias which was created by the file system in our previous test to write global variables into it
  • PUT sto api/users/${data.userId} endpoint, calls supertest.put() 
  • DELETE requests to api/users/${data.userId} endpoint, calls supertest.delete() 
  • validates response returned by the endpoints
  • removes data.json (similar to unsetting global variables) after all the tests are done

CODE: https://gist.github.com/velotiotech/80ac22df304961f7722257565fe69de3.js

And we are done with setting up a decent framework and just a command away!

CODE: https://gist.github.com/velotiotech/9abeb3824d852a66b3f208da35e7cb87.js

Once complete, the test results will be immediately visible on the terminal.

Test results HTML report is also generated as index.html under jest-stare/ 

jest-stare report

And test coverage details are created under coverage/my_reports/ in the workspace.

Test coverage report
Test coverage details

Similarly, other HTTP methods can also be tested, like OPTIONS - supertest.options() which allows dealing with CORS, PATCH - supertest.patch(), HEAD - supertest.head() and many more.

Wasn’t it a convenient and successful journey?

Conclusion

So, wrapping it up with a note that API testing needs attention, and as a QA, let’s abide by the concept of a testing pyramid which is nothing but the mindset of a tester and how to combat issues at a lower level and avoid chaos at upper levels, i.e. UI. 

Testing Pyramid

I hope you had a good read. Kindly spread the word. Happy coding!