Supertest & HTTP Integration
Supertest envia requisições HTTP para aplicações Express e Fastify no mesmo processo, sem a necessidade de vincular uma porta, tornando os testes de integração rápidos e seguros para execução paralela.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
import request from "supertest";
import { createApp } from "../src/app.js";
const res = await request(createApp()).get("/health");npm install -D supertest @types/supertestQuando usar:
- Testar rotas, ordem de middleware e códigos de status.
- Validar corpos de requisição/resposta JSON e cabeçalhos de autenticação.
- Evitar colisões de porta instáveis em CI paralela.
Exemplo de Trabalho
// src/app.ts
import express from "express";
export function createApp() {
const app = express();
app.use(express.json());
app.get("/health", (_req, res) => {
res.json({ status: "ok" });
});
app.post("/items", (req, res) => {
if (!req.body?.name) {
return res.status(400).json({ error: "name required" });
}
res.status(201).json({ id: "item_1", name: req.body.name });
});
return app;
}// test/app.http.test.ts
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import request from "supertest";
import { createApp } from "../src/app.js";
describe("HTTP API", () => {
it("GET /health retorna ok", async () => {
const res = await request(createApp()).get("/health");
assert.equal(res.status, 200);
assert.deepEqual(res.body, { status: "ok" });
});
it("POST /items valida o corpo", async () => {
const res = await request(createApp())
.post("/items")
.send({})
.set("Content-Type", "application/json");
assert.equal(res.status, 400);
assert.equal(res.body.error, "name required");
});
});O que isto demonstra:
- A factory
createApp()evita efeitos colaterais delisten(). - Supertest funciona com
node:test(não requer Jest). - Assert sobre
res.bodyJSON parseado, não strings brutas.
Mergulho Profundo
Como Funciona
- Supertest envolve o servidor HTTP do Node e injeta requisições através de um socket interno.
- Nenhuma porta de rede significa que os testes rodam em paralelo sem
EADDRINUSE. - A pilha de middleware executa identicamente à produção até que você simule dependências.
- Fastify: use
app.inject()nativamente ou Supertest apósapp.ready().
Alternativa Fastify inject
import Fastify from "fastify";
const app = Fastify();
app.get("/health", async () => ({ ok: true }));
await app.ready();
const res = await app.inject({ method: "GET", url: "/health" });
// res.statusCode, res.json()Notas de TypeScript
- Os tipos do Express 5 vêm com o pacote em stacks Node 24.
- Digite o retorno de
createApp()comoexpress.ApplicationouFastifyInstancepara ajuda do editor.
Armadilhas
- Chamar listen() no módulo do app - A porta é vinculada na importação; os testes competem com o servidor de produção. Correção: exportar uma factory; chamar
listen()apenas emserver.ts. - Singleton de DB mutável compartilhado - Testes paralelos corrompem os dados. Correção: rollback de transação por teste ou repositório em memória em testes HTTP unitários.
- Falta de
awaitna requisição - Supertest retorna umTest; é preciso usarawaitna promise em testes assíncronos. Correção: sempre usarawait request(...).get(). - Vazamento de estado de cookie/sessão - O agente persiste cookies entre chamadas não intencionalmente. Correção: usar
request.agent(app)apenas ao testar sessões; usarrequest(app)novo caso contrário. - Testar apenas o caminho feliz - Erros 500 não tratados. Correção: testes orientados por tabela para casos 400/401/404/409.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
Fastify inject | Código-fonte apenas Fastify | Aplicações Express |
| Porta real + fetch | Testar TLS ou edge HTTP/2 | Integração padrão |
| Testes de contrato Pact | Limite consumidor-provedor | API monolítica única |
FAQs
Supertest funciona com Express 5?
Sim. Supertest se conecta ao handler HTTP do Express Application como no Express 4.
Como testar rotas autenticadas?
await request(app).get("/me").set("Authorization", "Bearer test-token");Use tokens de teste ou substitua o middleware de autenticação em createApp({ auth: "test" }).
Posso testar uploads multipart?
Supertest suporta .attach() para dados de formulário multipart.
Como testar WebSockets?
Supertest é apenas HTTP. Use um cliente ws contra o servidor de teste ou utilitários de teste WS dedicados.
e2e do NestJS?
@nestjs/testing cria a aplicação; use Supertest request(app.getHttpServer()).
Por que não usar localhost:3000?
Vincular a porta é mais lento, instável em CI paralela e requer gerenciamento separado do ciclo de vida do processo.
Como simular o banco de dados?
Injete mocks de repositório ao chamar createApp({ repos: mocks }) - evite simular apenas na camada HTTP.
A ordem do middleware importa?
Sim - testes de integração pegam erros de autenticação-antes-do-parser que Supertest exercita em full stack.
Como testar respostas de streaming?
Assert sobre res.text ou eventos de stream; mais complexo - considere testes unitários focados nos manipuladores de stream.
Supertest com node:test ou Vitest?
Ambos funcionam; escolha o runner padrão do repositório; a API do Supertest não muda.
Relacionados
- Noções Básicas de Teste - posicionamento na pirâmide para testes HTTP
- Testcontainers - DB real por trás da camada HTTP
- Vitest - runner com ergonomia de mock
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, e NestJS 11.