From 1af83de38d015bced8e982f032e6ffbff4a232cf Mon Sep 17 00:00:00 2001 From: Lumia1108 Date: Sat, 3 Oct 2026 23:05:45 +0900 Subject: [PATCH] Test Express response forwarding Add regression coverage for forwarding response status, headers, and every streamed body chunk to Express. Codex was used to explain the relevant code and review the test. I personally wrote and verified the implementation. Assisted-by: Codex:GPT-5.6 --- packages/express/src/index.test.ts | 62 +++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/packages/express/src/index.test.ts b/packages/express/src/index.test.ts index 04cc600cf..d6de2ddf9 100644 --- a/packages/express/src/index.test.ts +++ b/packages/express/src/index.test.ts @@ -1,5 +1,10 @@ +import { createFederation, MemoryKvStore } from "@fedify/fedify"; import type { Request as ERequest, Response as EResponse } from "express"; +import express from "express"; +import { strict as assert } from "node:assert"; +import type { AddressInfo } from "node:net"; import { describe, test } from "node:test"; +import { integrateFederation } from "./index.ts"; interface MockFederation { fetch(request: Request, options: unknown): Promise; @@ -19,8 +24,15 @@ function createMockResponse(): { response: EResponse; ended: Promise; getBody(): string; + getHeader( + name: string, + ): string | number | readonly string[] | undefined; } { let body = ""; + const headers = new Map< + string, + string | number | readonly string[] + >(); let resolveEnded: () => void; const ended = new Promise((resolve) => { resolveEnded = resolve; @@ -31,7 +43,11 @@ function createMockResponse(): { response.statusCode = code; return response; }, - setHeader() { + setHeader( + name: string, + value: string | number | readonly string[], + ) { + headers.set(name.toLowerCase(), value); return response; }, write(chunk: Buffer | string) { @@ -47,6 +63,7 @@ function createMockResponse(): { response: response as unknown as EResponse, ended, getBody: () => body, + getHeader: (name) => headers.get(name.toLowerCase()), }; } @@ -113,12 +130,45 @@ describe("integrateFederation()", () => { await ended; assert.strictEqual(response.statusCode, 406); }); + + test("forwards the Fedify response status, headers, and streamed body to the Express response", async () => { + const encoder = new TextEncoder(); + const body = new ReadableStream({ + start(controller) { + controller.enqueue(encoder.encode("Hello ")); + controller.enqueue(encoder.encode("World")); + controller.close(); + }, + }); + + const mockFederation: MockFederation = { + fetch() { + return Promise.resolve( + new Response(body, { + status: 201, + headers: { + "Header-Test": "yes", + }, + }), + ); + }, + }; + + const middleware = integrateFederation( + mockFederation as never, + () => undefined, + ); + + const req = createMockRequest(); + const { response, ended, getBody, getHeader } = createMockResponse(); + + middleware(req, response, () => {}); + await ended; + assert.strictEqual(response.statusCode, 201); + assert.strictEqual(getHeader("Header-Test"), "yes"); + assert.strictEqual(getBody(), "Hello World"); + }); }); -import { createFederation, MemoryKvStore } from "@fedify/fedify"; -import express from "express"; -import { strict as assert } from "node:assert"; -import type { AddressInfo } from "node:net"; -import { integrateFederation } from "./index.ts"; // Large enough to fill the stream buffers that used to stall; see // .