Testing without a port

Call server.fetch with a Request - fast unit tests, no listen(), no network.

Prerequisites

  • Export the server instance (or a factory) from your app module
  • Do not call listen() during tests - use import.meta.main in the entrypoint

Portless tests

// server.ts
import { HttpServer, z } from "jsr:@webtools/expressapi";

export const server = new HttpServer()
  .get("/users/:id", (req, res) => res.json({ id: req.params.id }))
  .post("/users", (req, res) =>
    res.status(201).json({ name: req.body.name }), [], {
      body: z.object({ name: z.string().min(1) }),
    });

if (import.meta.main) server.listen(5050);
// server_test.ts
import { assertEquals } from "jsr:@std/assert";
import { server } from "./server.ts";

Deno.test("GET /users/:id", async () => {
  const response = await server.fetch(
    new Request("http://localhost/users/42"),
  );
  assertEquals(response.status, 200);
  assertEquals(await response.json(), { id: "42" });
});

Deno.test("POST /users validates body", async () => {
  const response = await server.fetch(
    new Request("http://localhost/users", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ name: "" }),
    }),
  );
  assertEquals(response.status, 400);
  const body = await response.json();
  assertEquals(body.success, false);
});

Deno.test("CORS preflight", async () => {
  const response = await server.fetch(
    new Request("http://localhost/users/42", {
      method: "OPTIONS",
      headers: {
        origin: "http://localhost:5173",
        "access-control-request-method": "GET",
      },
    }),
  );
  assertEquals(response.status, 204);
});

Related: Advanced.