test: tighten http common assertions

This commit is contained in:
Peter Steinberger
2026-05-10 22:48:40 +01:00
parent 3ae83962c1
commit 2d0f25e379

View File

@@ -34,6 +34,22 @@ beforeEach(() => {
resetDiagnosticEventsForTest();
});
function headerNames(setHeader: ReturnType<typeof vi.fn>): string[] {
return setHeader.mock.calls
.map((call) => call[0])
.filter((name): name is string => typeof name === "string");
}
function expectHeaderNotSet(setHeader: ReturnType<typeof vi.fn>, name: string): void {
expect(headerNames(setHeader)).not.toContain(name);
}
function mockCallRecord(mock: ReturnType<typeof vi.fn>, index: number): unknown[] {
const call = mock.mock.calls[index];
expect(call).toBeTruthy();
return call ?? [];
}
describe("setDefaultSecurityHeaders", () => {
it("sets X-Content-Type-Options", () => {
const { res, setHeader } = makeMockHttpResponse();
@@ -70,19 +86,19 @@ describe("setDefaultSecurityHeaders", () => {
it("does not set Strict-Transport-Security when not provided", () => {
const { res, setHeader } = makeMockHttpResponse();
setDefaultSecurityHeaders(res);
expect(setHeader).not.toHaveBeenCalledWith("Strict-Transport-Security", expect.anything());
expectHeaderNotSet(setHeader, "Strict-Transport-Security");
});
it("does not set Strict-Transport-Security for empty string", () => {
const { res, setHeader } = makeMockHttpResponse();
setDefaultSecurityHeaders(res, { strictTransportSecurity: "" });
expect(setHeader).not.toHaveBeenCalledWith("Strict-Transport-Security", expect.anything());
expectHeaderNotSet(setHeader, "Strict-Transport-Security");
});
it("does not set Strict-Transport-Security when opts is omitted", () => {
const { res, setHeader } = makeMockHttpResponse();
setDefaultSecurityHeaders(res, undefined);
expect(setHeader).not.toHaveBeenCalledWith("Strict-Transport-Security", expect.anything());
expectHeaderNotSet(setHeader, "Strict-Transport-Security");
});
});
@@ -138,7 +154,7 @@ describe("sendRateLimited", () => {
const { res, setHeader, end } = makeMockHttpResponse();
sendRateLimited(res);
expect(res.statusCode).toBe(429);
expect(setHeader).not.toHaveBeenCalledWith("Retry-After", expect.anything());
expectHeaderNotSet(setHeader, "Retry-After");
expect(end).toHaveBeenCalledWith(
JSON.stringify({
error: {
@@ -153,14 +169,14 @@ describe("sendRateLimited", () => {
const { res, setHeader } = makeMockHttpResponse();
sendRateLimited(res, 0);
expect(res.statusCode).toBe(429);
expect(setHeader).not.toHaveBeenCalledWith("Retry-After", expect.anything());
expectHeaderNotSet(setHeader, "Retry-After");
});
it("responds with 429 and no Retry-After when retryAfterMs is negative", () => {
const { res, setHeader } = makeMockHttpResponse();
sendRateLimited(res, -500);
expect(res.statusCode).toBe(429);
expect(setHeader).not.toHaveBeenCalledWith("Retry-After", expect.anything());
expectHeaderNotSet(setHeader, "Retry-After");
});
it("sets Retry-After (seconds, ceiled) when retryAfterMs is positive", () => {
@@ -209,9 +225,10 @@ describe("readJsonBodyOrError", () => {
it("returns the parsed body on success", async () => {
readJsonBodyMock.mockResolvedValueOnce({ ok: true, value: { hello: "world" } });
const { res } = makeMockHttpResponse();
const result = await readJsonBodyOrError(makeRequest(), res, 1024);
const req = makeRequest();
const result = await readJsonBodyOrError(req, res, 1024);
expect(result).toEqual({ hello: "world" });
expect(readJsonBodyMock).toHaveBeenCalledWith(expect.anything(), 1024);
expect(readJsonBodyMock).toHaveBeenCalledWith(req, 1024);
});
it("responds with 413 when the body is too large", async () => {
@@ -229,16 +246,12 @@ describe("readJsonBodyOrError", () => {
error: { message: "Payload too large", type: "invalid_request_error" },
}),
);
expect(events).toContainEqual(
expect.objectContaining({
type: "payload.large",
surface: "gateway.http.json",
action: "rejected",
bytes: 2048,
limitBytes: 1024,
reason: "json_body_limit",
}),
);
const event = events.find((entry) => entry.type === "payload.large");
expect(event?.surface).toBe("gateway.http.json");
expect(event?.action).toBe("rejected");
expect(event?.bytes).toBe(2048);
expect(event?.limitBytes).toBe(1024);
expect(event?.reason).toBe("json_body_limit");
});
it("responds with 408 when the request body times out", async () => {
@@ -366,8 +379,12 @@ describe("watchClientDisconnect", () => {
const { req, res } = buildReqRes(reqSocket, resSocket);
const controller = new AbortController();
watchClientDisconnect(req, res, controller);
expect(reqOn).toHaveBeenCalledWith("close", expect.any(Function));
expect(resOn).toHaveBeenCalledWith("close", expect.any(Function));
const reqOnCall = mockCallRecord(reqOn, 0);
const resOnCall = mockCallRecord(resOn, 0);
expect(reqOnCall[0]).toBe("close");
expect(typeof reqOnCall[1]).toBe("function");
expect(resOnCall[0]).toBe("close");
expect(typeof resOnCall[1]).toBe("function");
});
it("cleanup detaches the close listener from each socket", () => {