Files

37 lines
1.5 KiB
TypeScript

import { createServer, type IncomingHttpHeaders } from 'node:http'
import type { AddressInfo } from 'node:net'
/** Serves a `Request → Response` handler over a real socket (test helper). */
export async function serve(handler: (req: Request) => Promise<Response>): Promise<{ url: string; close: () => Promise<void> }> {
const server = createServer(async (req, res) => {
const chunks: Buffer[] = []
for await (const c of req) chunks.push(c as Buffer)
const headers = Object.entries(req.headers as IncomingHttpHeaders).flatMap(([k, v]) => (v === undefined ? [] : [[k, String(v)] as [string, string]]))
const request = new Request(`http://localhost${req.url}`, {
method: req.method,
headers,
body: req.method === 'GET' || req.method === 'HEAD' ? undefined : Buffer.concat(chunks),
})
const response = await handler(request)
res.writeHead(response.status, Object.fromEntries(response.headers))
if (!response.body) return void res.end()
const reader = response.body.getReader()
res.on('close', () => void reader.cancel().catch(() => {}))
try {
for (;;) {
const { done, value } = await reader.read()
if (done) break
res.write(value)
}
} finally {
res.end()
}
})
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve))
const { port } = server.address() as AddressInfo
return {
url: `http://127.0.0.1:${port}`,
close: () => new Promise((resolve) => (server.closeAllConnections(), server.close(() => resolve()))),
}
}