← Back
express jest testing

How I do integration test with jest and supertest

The component structure #

This week I'm in the process of moving the test files from a "test" directory to the "src" directory itself. This is a quite established practice inside javascript userland and it has very pleasant effects:

Here are the contents of the Step component:

folder with tests

The controller.*.spec.js contains all the integration tests. Since integration test can be quite long, I've made a test file for each controller endpoint. The index.js file contains the business logic (what in Rails we usually call the Service object) and index.spec.js is it's associated test.

I did no changes in how I run the tests since jest test runner look for files ending in .spec.js or .test.js regardless of where they are. Optionally, I can pass to the jest-cli a pattern so, to run all integration test all I have to do is: jest controller And jest will run all controller.*.spec.js files in all the directories.

Testing an express.js app #

This is the require statements of the controller.list-steps.spec.js file of the Step component:

requires for express

All the heavy work is done by the "supertest" library. It takes an entire express.js app, set up a server and send http request to it.

One thing I like from Javascript is that everything is quite explicit (declarative). For example, if you need to setup a database connection, you have to explicitly say it. So, we start by describing a context scenario (using the jest's "describe" function) and declaring which functions should be running before and after all tests of this file:

Zoom describe-controller.png controller

Inside the "StepController" scenario we describe another scenario:

A simple scenario

Here I use a helper function ("createWorkflow", defined at the end of the test, to reduce the noise) that insert into the database the testing data. An important thing to note is that I don't clear the database, just remove the data I've inserted, because tests in jest are running in parallel, so cleaning the database in one test would make others fail. For the same reason, I've timestamped some data (like user's permissions) to avoid collisions with data from other tests.

Finally, I created the test server (using supertest's request function), made the request and checked the output:

As you can see, the code is quite self explanatory, all with this async goodness. There's this nice "objectContaining" function that allows me to check only some attributes of a big object.

Testing coverage #

One nice feature of jest is that it gives you coverage reports. With this command I can run all test from the Step component:

jest app/components/step --coverage

And it returns back a coverage report, including line numbers of non-tested code: coverage report

That's all folks!