diff --git a/packages/express/deno.json b/packages/express/deno.json index c43bb9422..d24d5f86e 100644 --- a/packages/express/deno.json +++ b/packages/express/deno.json @@ -19,6 +19,7 @@ ] }, "tasks": { - "check": "deno fmt --check && deno lint && deno check *.ts" + "check": "deno fmt --check && deno lint && deno check *.ts", + "test": "deno test --allow-all" } } diff --git a/packages/express/package.json b/packages/express/package.json index 0701aec5c..174c5f2e2 100644 --- a/packages/express/package.json +++ b/packages/express/package.json @@ -58,6 +58,7 @@ "build:self": "tsdown", "build": "pnpm --filter @fedify/express... run build:self", "prepack": "pnpm build", - "prepublish": "pnpm build" + "prepublish": "pnpm build", + "test": "node --experimental-transform-types --test" } } diff --git a/packages/express/src/index.test.ts b/packages/express/src/index.test.ts new file mode 100644 index 000000000..8d94a05d2 --- /dev/null +++ b/packages/express/src/index.test.ts @@ -0,0 +1,104 @@ +import type { Request as ERequest, Response as EResponse } from "express"; +import { strict as assert } from "node:assert"; +import { describe, test } from "node:test"; +import { integrateFederation } from "./index.ts"; + +interface MockFederation { + fetch(request: Request, options: unknown): Promise; +} + +function createMockRequest(): ERequest { + return { + protocol: "http", + host: "localhost", + url: "/", + method: "GET", + headers: {}, + } as unknown as ERequest; +} + +function createMockResponse(): { + response: EResponse; + ended: Promise; + getBody(): string; +} { + let body = ""; + let resolveEnded: () => void; + const ended = new Promise((resolve) => { + resolveEnded = resolve; + }); + const response = { + statusCode: 200, + status(code: number) { + response.statusCode = code; + return response; + }, + setHeader() { + return response; + }, + removeHeader() { + return response; + }, + write(chunk: Buffer | string) { + body += chunk.toString(); + return true; + }, + end() { + resolveEnded(); + return response; + }, + send() { + return response; + }, + json() { + return response; + }, + }; + return { + response: response as unknown as EResponse, + ended, + getBody: () => body, + }; +} + +describe("integrateFederation()", () => { + test("waits for an async contextDataFactory and passes the resolved value to federation.fetch()", async () => { + let resolveContextData!: (value: string) => void; + let fetchCalled = false; + + const mockFederation: MockFederation = { + fetch(_request, options) { + fetchCalled = true; + const { contextData } = options as { contextData: unknown }; + return Promise.resolve(new Response(String(contextData))); + }, + }; + + const contextDataFactory = () => + new Promise((resolve) => { + resolveContextData = resolve; + }); + + const middleware = integrateFederation( + mockFederation as never, + contextDataFactory, + ); + + const req = createMockRequest(); + const { response, ended, getBody } = createMockResponse(); + let nextCalled = false; + + middleware(req, response, () => { + nextCalled = true; + }); + + await Promise.resolve(); + assert.strictEqual(fetchCalled, false); + + resolveContextData("Hello World"); + await ended; + + assert.strictEqual(nextCalled, false); + assert.strictEqual(getBody(), "Hello World"); + }); +});