← Back to archive

Repo of the Day

forwardemail/supertest

Published: Jan 15, 2023

Open repository ↗

Looks cool for testing HTTP servers in node, maybe stuff like express, nest, or fastify servers

Summary

Supertest is a Node.js library for testing HTTP servers through a fluent API built on top of the superagent HTTP client. You hand it an Express app, an http.Server, or a function, and it makes real HTTP requests against that server without requiring you to bind a real port. The project is MIT-licensed, written in JavaScript, and is the maintained fork used by the @forwardemail and @ladjs organizations.

What it is useful for

Supertest is useful for writing integration tests against any Node.js HTTP server. Because it binds servers to an ephemeral port automatically, tests don't collide on port numbers, and there is no manual teardown. It is framework-agnostic, so it pairs with Mocha, Jest, AVA, or no test runner at all. The README documents a number of concrete use cases:

  • Asserting response status codes, headers, and bodies via chained .expect() calls
  • Testing JSON endpoints with content-type and content-length checks
  • Hitting protected routes with .auth(username, password)
  • Uploading multipart form data with .field() and .attach()
  • Simulating a logged-in user across multiple requests using request.agent(app), which persists cookies between calls
  • Asserting cookie attributes such as domain, path, httpOnly, expires, and max-age using the request.cookies helper
  • Testing HTTP/2 endpoints by passing { http2: true } to request() or request.agent()
  • Dropping down to the lower-level superagent API (.write(), .pipe(), etc.) for cases the higher-level assertions do not cover

How engineers can use it

The documented setup is a single install command:

npm install supertest --save-dev

Then require('supertest') in a test file. A typical Mocha test from the README looks like this:

const request = require('supertest');
const express = require('express');

const app = express();
app.get('/user', function(req, res) {
  res.status(200).json({ name: 'john' });
});

describe('GET /user', function() {
  it('responds with json', function(done) {
    request(app)
      .get('/user')
      .set('Accept', 'application/json')
      .expect('Content-Type', /json/)
      .expect(200, done);
  });
});

The same pattern works with promises, async/await, or raw .end(function(err, res) { ... }) callbacks, all of which the README shows. Assertions run in the order they are chained, so a custom .expect(function(res) { ... }) can mutate res.body before a later structural check.

A documented gotcha: when using .end(), failing .expect() assertions do not throw — they are returned as the first argument to the .end() callback, so you must forward that error to done(err) or rethrow it. The README does not describe a browser entry point, so for anything outside HTTP assertions against a Node server, the README redirects you to the underlying superagent client.