API Testing

Supertest

Supertest ejecuta tu aplicación Node HTTP en el mismo proceso y convierte las pruebas de API en simples aserciones de estado, encabezados y cuerpo; sin servidores que iniciar, sin puertos que gestionar y sin redes que simular.

beginner14 min readUpdated 16 sept 2026
posts.test.ts
ts
// posts.test.ts
import request from "supertest";
import { expect, test } from "vitest";
import app from "../src/app.js";

test("GET /posts returns a list", async () => {
  const res = await request(app)
    .get("/posts")
    .expect("Content-Type", /json/)
    .expect(200);

  expect(res.body).toEqual(
    expect.arrayContaining([expect.objectContaining({ id: 1 })]),
  );
});
Basado en
superagent
Se ejecuta contra
Tu objeto de aplicación
Test runners
Vitest, Jest, node:test
Red
En proceso, puerto efímero
Estilo
Aserciones encadenables
Primera versión
2011

Por que importa

Por qué Supertest es fundamental

Tu app, sin servidor

Apunta Supertest a la función de aplicación exportada y este iniciará un servidor efímero para la prueba y luego lo cerrará. No hay puertos que elegir ni procesos que supervisar.

Peticiones encadenables

La cadena al estilo superagent —método, set, send, query— se lee como la petición HTTP que estás describiendo, por lo que las pruebas sirven también como documentación.

Aserciones en la cadena

expect(status), expect(header, value) y expect(body) fallan adjuntando la respuesta real, lo que acorta el ciclo desde la prueba fallida hasta la causa.

La imagen completa

Tres ideas clave para entenderlo

Le entregas a Supertest una aplicación, este construye una petición por ti y la respuesta queda disponible para hacer aserciones como cualquier otro objeto.

El objeto de aplicación

Importar

Exporta el request listener desde app.ts y mantén listen() en server.ts. Las pruebas importan la aplicación y nunca abren un puerto fijo.

La petición

Componer

get, post, set, send y query construyen una llamada HTTP. Los objetos se serializan a JSON y se establece el Content-Type correspondiente automáticamente.

La respuesta

Aseverar

status, headers, body y text son valores simples, por lo que puedes hacer aserciones sobre ellos con el mismo expect que usas en cualquier otra parte.

HTML5 de un vistazo

La caja de herramientas de Supertest

request(app)

Entrega la aplicación a Supertest y obtén un constructor de peticiones encadenable.

Métodos

.get, .post, .put, .patch y .delete mapean directamente a los verbos HTTP.

Cuerpos

.send({...}) serializa a JSON y establece el Content-Type por ti.

Autenticación

.set('Authorization', ...) o .auth() adjuntan credenciales a la petición.

Respuesta

res.status, res.headers y res.body están listos para las aserciones.

Subidas

.attach() y .field() construyen envíos de formularios multipart.

Flujo

Flujo de una prueba con Supertest

Cada prueba de Supertest sigue el mismo camino, desde la importación de la aplicación hasta la limpieza de los datos manipulados.

  1. 1

    Importar la aplicación

    Importa el request listener exportado, no un servidor en ejecución. Es el mismo objeto que utiliza tu punto de entrada de producción.

  2. 2

    Construir la petición

    Llama a request(app) y encadena el método, la ruta, los encabezados, la query y el cuerpo que quieras probar.

  3. 3

    Enviar y esperar

    Usa await con la cadena. Supertest inicia un servidor efímero, despacha la petición y resuelve con la respuesta.

  4. 4

    Aseverar estado y encabezados

    Verifica primero el código de estado y el Content-Type; estos detectan errores de enrutamiento y serialización antes que las aserciones del cuerpo.

  5. 5

    Aseverar el cuerpo

    Compara el cuerpo parseado con la estructura que promete el contrato, utilizando el expect de tu test runner para cualquier cosa compleja.

  6. 6

    Limpieza

    Restablece los datos que manipulaste y cierra la base de datos o el pool de conexiones para que la siguiente prueba comience desde un estado conocido.

La guia completa

Supertest: Todo lo que necesitas saber

¿Qué es Supertest?

Supertest es una librería de aserciones HTTP para Node.js. Toma un objeto de aplicación —ya sea una app de Express, una instancia de Fastify o un request listener básico de http— y te permite realizar peticiones hacia ella mediante una API encadenable para luego validar la respuesta.

Está construida sobre superagent, por lo que la parte de las peticiones te resultará familiar si ya has utilizado esa librería. Lo que Supertest añade es la ergonomía para el testing: puedes pasar una app directamente en lugar de una URL, el ciclo de vida del servidor se gestiona automáticamente y puedes adjuntar aserciones de .expect() a la cadena.

Lo más importante que debes entender es que Supertest no ejecuta un navegador ni inicia tu servidor de producción. Crea un servidor HTTP de corta duración en el mismo proceso, vinculado a un puerto efímero en localhost, envía la petición y lo cierra cuando se resuelve la respuesta. De este modo, tu test interactúa con el stack HTTP real —códigos de estado, headers, cuerpos, serialización— sin el coste ni la inestabilidad de un proceso independiente.

Por qué testear in-process

La mayor parte de las complicaciones en las pruebas de HTTP provienen del servidor, no de la solicitud. Un proceso independiente requiere un puerto, un tiempo de espera para el arranque, un health check y un proceso de cierre. Los puertos fijos generan colisiones en CI, y una condición de carrera entre listen y la primera solicitud produce fallos que parecen errores de la aplicación.

El testing in-process elimina todo eso. No hay un proceso que iniciar, por lo que no hace falta un chequeo de disponibilidad. No hay un puerto fijo, así que los archivos de prueba paralelos no interfieren entre sí. No hay un límite de red, por lo que un fallo apunta a tu handler y no al entorno.

Aun así, obtienes todo el pipeline de la solicitud: el middleware, el routing, el body parsing, la autenticación y el manejo de errores se ejecutan exactamente igual que en producción, porque es el mismo código. Lo que sacrificas son las cosas que solo un navegador real o una red real pueden proporcionar: la ejecución de JavaScript, un motor de renderizado y el comportamiento exacto de un proxy delante de tu app.

Exporta la app, no el listener

Para que Supertest pueda importar tu app, esta debe ser exportable. Un error común es definir las rutas y llamar a listen en el mismo módulo; esto inicia el servidor en el momento en que se importa el archivo, lo que provoca conflictos de puertos en tus tests.

Separa estas dos responsabilidades:

// src/app.ts
import express from "express";
import { postsRouter } from "./routes/posts.js";

export const app = express();

app.use(express.json());
app.use("/posts", postsRouter);

app.use((err, req, res, next) => {
  res.status(err.status ?? 500).json({ error: err.code ?? "internal_error" });
});
// src/server.ts
import { app } from "./app.js";

app.listen(3000, () => console.log("listening on http://localhost:3000"));

Ahora src/app.ts exporta el request listener y nada más. Los tests lo importan, y el entorno de producción lo importa desde server.ts. Esta simple separación es la diferencia entre una API que puedes testear en milisegundos y una que tienes que bootear completamente.

El app de Express es en sí mismo una función con la firma (req, res), que es exactamente lo que espera el http.createServer de Node.js. Es por eso que request(app) funciona sin necesidad de ningún adaptador. Fastify requiere app.server o un app.ready() con await, y un handler básico de Node.js funciona directamente.

Realizando una petición

Una petición comienza con request(app) y el método HTTP. Todos los métodos que superagent soporta están disponibles, y la cadena devuelve el mismo objeto de petición para que las llamadas puedan apilarse.

import request from "supertest";
import app from "../src/app.js";

await request(app).get("/posts");
await request(app).post("/posts").send({ title: "Hello" });
await request(app).patch("/posts/1").send({ title: "Updated" });
await request(app).delete("/posts/1");

send serializa un objeto a JSON y establece el encabezado Content-Type automáticamente. Una cadena de texto se envía tal cual, lo cual es útil cuando quieres probar a propósito un cuerpo mal formado.

Los encabezados se establecen con set, ya sea uno por uno o como un objeto. Los parámetros de consulta son más limpios a través de query, que los codifica y los añade por ti.

await request(app)
  .get("/posts")
  .query({ page: 2, perPage: 10 })
  .set("Accept", "application/json")
  .set({ "X-Request-Id": "test-1" });

La URL resultante es /posts?page=2&perPage=10. Si necesitas un cuerpo en bruto — XML, una cadena de texto simple, un payload deliberadamente corrupto — pasa set("Content-Type", ...) y send la cadena de texto.

Haciendo aserciones sobre la respuesta

La respuesta es un objeto normal con status, headers, body y text. Puedes hacer aserciones sobre ella utilizando el expect de tu test runner, o puedes usar el .expect() de Supertest directamente en la cadena.

const res = await request(app).get("/posts").expect(200);

expect(res.headers["content-type"]).toMatch(/application\/json/);
expect(res.body).toHaveLength(3);

El .expect() de Supertest es conveniente porque, en caso de fallo, incluye la respuesta completa en el mensaje de error, lo cual suele ser suficiente para ver qué salió mal sin necesidad de añadir líneas de log.

await request(app)
  .get("/posts")
  .expect("Content-Type", /json/)
  .expect(200);

.expect() acepta un código de estado, el nombre y valor de un encabezado, un cuerpo para igualdad profunda (deep equality), o una función que recibe la respuesta y puede lanzar un error. La forma de función es la “salida de emergencia” cuando una aserción requiere lógica adicional.

await request(app)
  .get("/posts")
  .expect((res) => {
    if (!res.body.every((p: { id: number }) => p.id > 0)) {
      throw new Error("every post must have a positive id");
    }
  });

Prefiere el expect del runner para cualquier cosa que vaya más allá de la línea de estado y el tipo de contenido. Ofrece mejores diffs, soporta matchers como toMatchObject y arrayContaining, y mantiene el estilo de las aserciones consistente con el resto de tu suite de pruebas.

Combinando Supertest con tu test runner

Supertest no es un test runner. Se encarga de construir peticiones y puede realizar aserciones sobre las respuestas, pero no descubre tests, no proporciona describe ni it, no hace mock de módulos ni reporta resultados. Esa tarea le corresponde a Vitest, Jest o node:test.

Ambos se integran perfectamente porque una petición de Supertest es “thenable”. Al usar await, se resuelve la respuesta, por lo que un test es simplemente una función async.

import request from "supertest";
import { beforeEach, describe, expect, it } from "vitest";
import app from "../src/app.js";

describe("POST /posts", () => {
  beforeEach(async () => {
    await resetDatabase();
  });

  it("creates a post", async () => {
    const res = await request(app)
      .post("/posts")
      .send({ title: "Hello" })
      .expect(201);

    expect(res.body.title).toBe("Hello");
  });
});

Si olvidas usar await, el test pasará antes incluso de que se envíe la petición y el fallo aparecerá más tarde como una “unhandled rejection”. Usa await en await petición, incluso en aquellas cuya única aserción sea .expect().

Pruebas de autenticación

La autenticación es simplemente un header o una cookie, por lo que ambos son fáciles de probar.

Para los bearer tokens, establece el header Authorization. Firma un token con el mismo secreto de prueba que utiliza la aplicación en lugar de llamar al proveedor de identidad real.

const token = await signTestToken({ sub: "user_1", scope: "read:posts" });

await request(app).get("/posts").expect(401);

await request(app)
  .get("/posts")
  .set("Authorization", `Bearer ${token}`)
  .expect(200);

Para las cookies de sesión, request.agent(app) mantiene un cookie jar entre peticiones, lo que imita el comportamiento de un navegador tras iniciar sesión.

const agent = request.agent(app);

await agent
  .post("/login")
  .send({ email: "[email protected]", password: "secret" })
  .expect(204);

await agent.get("/me").expect(200);

Cuando ya tengas el valor de una cookie, establécelo directamente. Las cookies se pasan como un array o como una cadena separada por puntos y coma.

await request(app).get("/me").set("Cookie", ["session=abc123"]).expect(200);

Prueba los casos negativos con el mismo cuidado que el happy path: sin token, un token expirado, un token para otra audiencia y un token válido pero sin el scope requerido. Esas cuatro pruebas te protegen mucho más que un único caso de éxito.

Configuración y limpieza de datos

Supertest no tiene una postura definida sobre la base de datos, lo que significa que una base de datos compartida filtrará el estado entre tests a menos que la reinicies. Existen tres estrategias comunes.

Reiniciar antes de cada test. Vacía las tablas que utiliza la suite en beforeEach. Es simple y predecible, y el coste es aceptable para suites pequeñas.

beforeEach(async () => {
  await db.query("TRUNCATE posts RESTART IDENTITY CASCADE");
  await db.query("INSERT INTO posts (id, title) VALUES (1, 'Seeded')");
});

Una transacción por test. Si tu app y tu test comparten la misma conexión, envuelve cada test en una transacción y haz un rollback en afterEach. Esto es rápido y deja la base de datos intacta, pero solo funciona cuando la app utiliza el mismo cliente, lo cual no siempre ocurre a través de HTTP.

Una base de datos fresca por archivo de test. Inicia una base de datos en memoria o en un contenedor para el archivo, ejecuta las migraciones y descártala al finalizar. Esto proporciona el aislamiento más fuerte y es el enfoque en el que se asientan la mayoría de las suites de integración, a costa de que el primer test sea más lento.

Cualquiera que sea tu elección, cierra el pool de conexiones en afterAll. Un pool abierto mantiene vivo el proceso de Node.js y convierte una suite exitosa en un job de CI colgado.

Probando los “unhappy paths”

Una ruta no está probada hasta que se prueban sus fallos. El código de estado es parte del contrato, así que asírtelo explícitamente.

await request(app).get("/posts/999").expect(404);
await request(app).post("/posts").send({}).expect(422);
await request(app).get("/admin").expect(403);

Un fallo de validación debería indicarte qué campo falló, no solo que algo salió mal.

const res = await request(app)
  .post("/posts")
  .send({ title: "" })
  .expect(422);

expect(res.body).toEqual({
  error: "validation_error",
  fields: { title: "required" },
});

Las distinciones son importantes. 400 es una solicitud malformada, 401 significa no autenticado, 403 significa autenticado pero sin permisos, 404 significa que el recurso no existe y 422 significa que el cuerpo se parseó pero falló la validación. Asertar el código incorrecto es un bug en el test que oculta un bug en la aplicación.

Carga de archivos y multipart

Supertest construye solicitudes multipart utilizando attach para los archivos y field para los campos del formulario adjuntos. Puedes pasar un buffer o una ruta; cuando pases un buffer, asígnale un nombre de archivo para que el servidor reciba uno coherente.

await request(app)
  .post("/users/1/avatar")
  .field("caption", "Profile picture")
  .attach("avatar", Buffer.from("fake-image"), "avatar.png")
  .expect(201);

Prueba también los rechazos: un archivo faltante, un archivo que supere el límite de tamaño y un tipo MIME no permitido. Las cargas de archivos son uno de los lugares más comunes donde suelen esconderse brechas de validación.

Probando la paginación, el filtrado y el ordenamiento

Los query strings son parte del contrato de la API, por lo que merecen tener pruebas. query los hace más legibles, y validar la longitud y el orden del cuerpo permite detectar errores de “off-by-one” y fallos en los valores por defecto.

test("GET /posts paginates", async () => {
  await seedPosts(25);

  const page1 = await request(app)
    .get("/posts")
    .query({ page: 1, perPage: 10 })
    .expect(200);

  expect(page1.body).toHaveLength(10);
  expect(page1.body[0].id).toBe(1);

  const page3 = await request(app)
    .get("/posts")
    .query({ page: 3, perPage: 10 })
    .expect(200);

  expect(page3.body).toHaveLength(5);
});

Prueba los límites, no solo el centro: la primera página, la última página, una página más allá del final y un perPage inválido que debería ser limitado o rechazado.

await request(app)
  .get("/posts")
  .query({ page: 999 })
  .expect(200)
  .expect((res) => {
    if (res.body.length !== 0) throw new Error("expected an empty page");
  });

await request(app).get("/posts").query({ perPage: 10_000 }).expect(400);

El filtrado y el ordenamiento son igual de testeables, y es precisamente donde la falta de un índice o un ORDER BY incorrecto se manifiesta como un bug sutil.

const res = await request(app)
  .get("/posts")
  .query({ status: "published", sort: "-createdAt" })
  .expect(200);

expect(
  res.body.every((p: { status: string }) => p.status === "published"),
).toBe(true);

Redirecciones, cookies y otros detalles de HTTP

No todas las respuestas son un cuerpo JSON. Los códigos de estado como 301, 302 y 304, y los headers como Location, Set-Cookie y Cache-Control, suelen ser el comportamiento principal que se desea testear.

Por defecto, supertest no sigue las redirecciones, que es precisamente lo que necesitas cuando estás validando la redirección en sí.

const res = await request(app).get("/old-posts").expect(301);

expect(res.headers.location).toBe("/posts");

Si lo que importa es la cadena de redirecciones, redirects(1) sigue un salto y resuelve con la respuesta final.

await request(app).get("/old-posts").redirects(1).expect(200);

Las cookies son visibles en set-cookie, y el jar del agente te permite validar que un login haya establecido los atributos correctos sin necesidad de decodificar el valor.

const res = await request.agent(app)
  .post("/login")
  .send({ email: "[email protected]", password: "secret" })
  .expect(204);

const cookie = res.headers["set-cookie"][0];
expect(cookie).toContain("HttpOnly");
expect(cookie).toContain("SameSite=Lax");

Las solicitudes condicionales, la compresión y los headers de caché merecen una prueba cuando dependes de ellos, ya que un proxy o CDN cambiará el comportamiento sin avisar si los headers son incorrectos.

Acelerando la suite

Una suite de Supertest suele ser rápida, pero existen algunos hábitos que ayudan a mantenerla así a medida que crece.

Reutiliza la configuración costosa en beforeAll y reinicia solo las partes mutables por cada test. Arrancar un contenedor o migrar un esquema una vez por archivo, en lugar de una vez por test, puede ahorrar minutos en una suite extensa.

Ejecuta los archivos de test en paralelo. Tanto Vitest como Jest hacen esto por defecto y, dado que cada solicitud de Supertest utiliza un puerto efímero, no hay colisiones que resolver. Lo único que debes garantizar es que los archivos no compartan filas de la base de datos.

Omite el trabajo irrelevante en los tests que solo realizan lecturas. Si una ruta solo necesita un usuario y un post, no cargues todo el conjunto de fixtures. Las fixtures más pequeñas son más rápidas de crear y más fáciles de analizar.

# run one file while iterating
pnpm exec vitest run test/posts.test.ts

# watch the file you are editing
pnpm exec vitest test/posts.test.ts

Finalmente, mantén los unit tests para la lógica pura y deja que los tests HTTP cubran la integración. Una suite que procesa cada cálculo a través de una solicitud completa es lenta y no aporta confianza adicional.

Organizando una suite de pruebas

Imita la estructura del código fuente para que, cuando una prueba falle, apunte a un archivo que puedas localizar fácilmente. Si la aplicación tiene src/routes/posts.ts, coloca test/posts.test.ts junto a ello en el árbol de pruebas.

Mantén la configuración compartida en un número reducido de helpers:

  • Un test/app.ts que construya la aplicación con la configuración de pruebas.
  • Un test/db.ts que migre, trunque y cierre la base de datos.
  • Un test/factories.ts con funciones que creen usuarios, posts y tokens.
  • Un test/tokens.ts que firme un token con el secreto de pruebas.
// test/factories.ts
export async function createUser(overrides: Partial<User> = {}) {
  return db.user.create({
    data: { email: "[email protected]", role: "member", ...overrides },
  });
}

Las factories mantienen las pruebas legibles porque el valor interesante es la anulación (override). Una prueba que dice createUser({ role: "admin" }) comunica su intención de una manera que un muro de campos literales no logra hacer.

Manteniendo los tests independientes

Cada test debe pasar por sí solo y en cualquier orden. Esta propiedad es lo que permite que un runner paralelice los archivos y evita que un único fallo se convierta en una cascada de una docena de errores engañosos.

Los enemigos de la independencia son el estado mutable compartido: un contador a nivel de módulo, una fila sembrada que otro test elimina, un reloj mockeado que nunca se restaura o una base de datos que solo se configura una vez. Reinicia las piezas de las que dependa cada test y nunca confíes en que un test previo haya creado algo.

Cuando un fixture es genuinamente costoso —una base de datos migrada, un contenedor en ejecución— créalo una sola vez en beforeAll y reinicia las partes mutables en beforeEach. La distinción radica entre la configuración de solo lectura y la configuración que cambia.

Mejores prácticas

  • Exporta la app desde app.ts y mantén listen() en server.ts.
  • Usa await en cada petición; un await faltante es un pase silencioso.
  • Valida el código de estado y el tipo de contenido antes que el cuerpo.
  • Prueba los caminos negativos — 400, 401, 403, 404, 422 — no solo el camino feliz.
  • Firma los tokens de prueba con un secreto de test en lugar de llamar al proveedor real.
  • Reinicia los datos que toque cada prueba y cierra el pool en afterAll.
  • Mantén un solo comportamiento por prueba para que un fallo identifique exactamente qué se rompió.
  • Prefiere el expect del runner para las aserciones del cuerpo y .expect() para la línea de estado.
  • Ejecuta la suite contra el mismo stack de middleware que utiliza producción.

Errores comunes

  • Llamar a listen() en el módulo importado, provocando que cada archivo de prueba abra un puerto.
  • Olvidar await, lo que hace que una prueba pase antes de que se envíe la solicitud.
  • Compartir una fila de la base de datos entre pruebas y depender del orden de ejecución.
  • Probar el framework —asegurando que Express procese JSON— en lugar de probar tu propio código.
  • Validar un 200 cuando la ruta debería devolver un 404.
  • Dejar el pool de la base de datos abierto, impidiendo que el proceso finalice.
  • Hacer un mock de la base de datos tan exhaustivo que la prueba solo demuestre que el mock funciona.
  • Verificar el cuerpo con una coincidencia de cadenas cuando un comparador estructural sería más claro.
  • Ignorar encabezados como Location, Set-Cookie y las directivas de caché.

Próximos pasos

Supertest cubre el límite de HTTP y se complementa con todo lo que lo rodea. Lee sobre Vitest para conocer el runner que ejecutará estas pruebas, o Jest si tu proyecto ya utiliza Jest. La guía de Express explica el objeto app que le estás pasando a Supertest, y la sección de REST cubre los códigos de estado y la semántica que codifican tus aserciones. Una vez que la API esté cubierta, End-to-End Testing muestra cómo validar los mismos flujos a través de un navegador real.

En la practica

Desde la primera petición hasta datos reales

Cuatro pruebas que cubren la estructura de una suite de API típica.

posts.test.ts
import request from "supertest";
import { expect, test } from "vitest";
import app from "../src/app.js";

test("GET /posts returns a list", async () => {
  const res = await request(app).get("/posts").expect(200);

  expect(res.headers["content-type"]).toMatch(/json/);
  expect(res.body).toHaveLength(3);
});

Importar la app vs iniciar un servidor

Supertest puede probar un servidor en ejecución mediante una URL, pero importar la aplicación mantiene la prueba en un solo proceso y elimina los problemas de puertos y tiempos.

Preferir
import app from "../src/app.js";
import request from "supertest";

const res = await request(app).get("/health").expect(200);
Evitar
const server = app.listen(3000);

const res = await fetch("http://localhost:3000/health");
expect(res.status).toBe(200);

server.close();
// a fixed port collides in CI and the server
// may not be ready when fetch runs

Aseverar el contrato vs aseverar internos

Prueba la respuesta que el cliente realmente ve. Acceder a la base de datos o a helpers privados acopla la suite a detalles de implementación que pueden cambiar.

Preferir
const res = await request(app)
  .post("/posts")
  .send({ title: "Hello" })
  .expect(201);

expect(res.body).toMatchObject({ title: "Hello" });
Evitar
await request(app)
  .post("/posts")
  .send({ title: "Hello" })
  .expect(201);

const [row] = await db.query("SELECT * FROM posts");
expect(row.title).toBe("Hello");
// breaks the moment the schema or query changes

Compromisos

Dónde termina Supertest

Supertest es un constructor de peticiones y un ayudante de aserciones, no una estrategia de pruebas. Ten claro qué deja deliberadamente en tus manos.

Strengths

  • Casi nada que configurar

    Si ya tienes un objeto de aplicación y un test runner, una sola importación es toda la instalación.

  • Rápido y hermético

    Las pruebas se ejecutan en el mismo proceso con un puerto efímero, por lo que no hay servicios externos que iniciar ni inestabilidad de red.

  • Se lee como la petición

    La cadena refleja HTTP, lo que hace que los fallos sean fáciles de leer y las nuevas pruebas rápidas de escribir.

Trade-offs

  • No gestiona el estado

    Supertest no tiene fixtures ni transacciones. Mantener la base de datos limpia entre pruebas es enteramente tu responsabilidad.

  • No puede detectar errores de renderizado

    Todo lo que esté debajo del límite de HTTP es invisible. Una respuesta 200 no dice nada sobre si la UI puede utilizarla.

  • No es un navegador

    No se ejecuta JavaScript, las cookies no se aplican como en un navegador, y las redirecciones y CORS se comportan de manera diferente.

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Supertest?

Nuestro tutorial interactivo te guia a traves de Supertest paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.