Today’s web apps rarely live alone. They often make requests to external APIs via HTTP requests.
Fortunately, testing these kinds of code isn’t too hard since we can mock the HTTP responses. This means that our tests don’t have to make the requests in our tests, which is critical for writing repeatable and independent tests.
In this piece, we’ll look at how to test an Express app that interacts with an external API.
Creating a Simple App
First, we create the app that we’ll test. The app will get a random joke from the Chuck Norris Jokes API.
Next, we create an empty project folder and run:
npm init -y
To create an empty package.json
file with the default answers.
Next, we install Express and Node-Fetch to create the app and get data from APIs, respectively.
We run:
npm i express node-fetch
To install the packages.
Then we create app.js
and add:
To make the app that gets the joke and returns it as the response.
Adding the Test
To add the test, we use the Jest test runner to run the test and check the results, Nock to mock the response for the request that we made in app.js
, and Supertest to run the Express app and get the response that we can check.
To do this, we run:
npm i nock supertest jest
Then we create app.test.js
for the test code and then add:
In the file.
The code above starts by including our app from app.js
and the libraries we use for building the test.
const app = require('./app');
const nock = require('nock');
const request = require('supertest');
The first line above imports the Express app instance from app.js
. Then the other two lines import the Nock and Supertest libraries, respectively.
Then we add the skeleton for the test by calling test
from Jest and pass in the description and async
function since we’ll use the promise version of Supertest.
Then using Nock, we mock the response as follows:
As we can see, the mock request is a GET request, which is the same as what we had in app.js
. Also, the URL is the same as what we had there.
The difference is that we return a 200 response with the mockResponse
object in the test.
Now it doesn’t matter what the actual API returns. Nock will intercept the request and always return the content of mockResponse
as the response body for the request made in our route in app.js
.
Then we just have to call the route with Supertest as follows:
const res = await request(app).get('/');
To call the route in app.js
and then check the response as follows:
expect(res.status).toBe(200);
expect(res.body).toEqual(mockResponse);
The toEqual
method checks for deep equality so we can pass in the whole object to check.
Photo by Filip Mroz on Unsplash.
Running the Test
Now to run our test, we have to add:
"test": "jest --forceExit"
To the scripts
section of package.json
.
We need the --forceExit
option so that the test will exit once the test is run. This is a bug that’s yet to be resolved.
Now we can run the test by running:
npm test
Then we should get:
We should get the same thing no matter how many times we run the test since we mocked the response of the API.
The real API returns something different every time we make a request to it, so we can’t use it for our tests.
Even if we could, it’d be much slower and the API might not always be available.
Conclusion
With Nock, we can mock responses easily for external API requests in our app. Then we can focus on just running our app’s code and checking the results.
Now we have tests that run fast and produce repeatable results that don’t depend on anything external to the tests.