Search code examples
node.jsexpresshttpserver

How can I test my Express app without running a live server?


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?


Solution

  • 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.