In many web frameworks, it is possible to perform integration testing on an app without spinning up a live server (see docs from Flask, Fastify and Laravel). Simulating the network rather than actually sending requests over localhost can have a significant performance improvement. For example, in a benchmark I made, using Flask's test client was nearly 5x faster (3 seconds) than sending real requests with the requests
library (14 seconds).
However, when using Express, I have not been able to find a way to achieve this. Tools such as supertest
appear to quietly start the server on an ephemeral port, rather than simulating the network.
How can I perform simulated requests to an Express server, rather than starting the server and requesting to it over localhost?
You can use the light-my-request
library, which is compatible with Express, as well as many other Node-based web frameworks.
// server.js
import express, { json } from 'express';
const server = express();
server.use(json());
server.post('/my/route', (req, res) => {
const { name } = req.body;
res.json({ greeting: `Hello, ${name}` });
});
export default server;
// server.test.js
import server from './server.js';
import inject from 'light-my-requests';
test('Basic request', async () => {
const response = await inject(server, {
method: 'POST',
url: '/my/route',
headers: { 'Content-Type': 'application/json' },
payload: JSON.stringify({ name: 'Maddy' }),
};
const json = JSON.parse(response.payload);
expect(json).toStrictEqual({ greeting: 'Hello, Maddy' });
});
The performance is about 50% faster (4.3 seconds) than using the fetch API (6.5 seconds), at least in the benchmark I ran.