Skip to content

Commit e2723d3

Browse files
committed
Tests for passing custom SSE headers
1 parent c828067 commit e2723d3

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

src/client/sse.test.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { SSEClientTransport } from "./sse.js";
2+
import { createServer, type Server } from "http";
3+
import { JSONRPCMessage } from "../types.js";
4+
import { AddressInfo } from "net";
5+
6+
describe("SSEClientTransport", () => {
7+
let server: Server;
8+
let transport: SSEClientTransport;
9+
let baseUrl: URL;
10+
11+
beforeEach((done) => {
12+
// Create a test server that will receive the EventSource connection
13+
server = createServer((req, res) => {
14+
// Store the received headers for verification
15+
(server as any).lastRequest = req;
16+
17+
// Send SSE headers
18+
res.writeHead(200, {
19+
"Content-Type": "text/event-stream",
20+
"Cache-Control": "no-cache",
21+
"Connection": "keep-alive"
22+
});
23+
24+
// Send the endpoint event
25+
res.write("event: endpoint\n");
26+
res.write(`data: ${baseUrl.href}\n\n`);
27+
});
28+
29+
// Start server on random port
30+
server.listen(0, "127.0.0.1", () => {
31+
const addr = server.address() as AddressInfo;
32+
baseUrl = new URL(`http://127.0.0.1:${addr.port}`);
33+
done();
34+
});
35+
});
36+
37+
afterEach((done) => {
38+
transport?.close().then(() => {
39+
server.close(done);
40+
});
41+
});
42+
43+
it("uses custom fetch implementation from EventSourceInit to add auth headers", async () => {
44+
const authToken = "Bearer test-token";
45+
46+
// Create a fetch wrapper that adds auth header
47+
const fetchWithAuth = (url: string | URL, init?: RequestInit) => {
48+
const headers = new Headers(init?.headers);
49+
headers.set("Authorization", authToken);
50+
return fetch(url.toString(), { ...init, headers });
51+
};
52+
53+
transport = new SSEClientTransport(baseUrl, {
54+
eventSourceInit: {
55+
fetch: fetchWithAuth
56+
}
57+
});
58+
59+
await transport.start();
60+
61+
// Verify the auth header was received by the server
62+
const headers = (server as any).lastRequest.headers;
63+
expect(headers.authorization).toBe(authToken);
64+
});
65+
66+
it("passes custom headers to fetch requests", async () => {
67+
const customHeaders = {
68+
Authorization: "Bearer test-token",
69+
"X-Custom-Header": "custom-value"
70+
};
71+
72+
transport = new SSEClientTransport(baseUrl, {
73+
requestInit: {
74+
headers: customHeaders
75+
}
76+
});
77+
78+
await transport.start();
79+
80+
// Mock fetch for the message sending test
81+
global.fetch = jest.fn().mockResolvedValue({
82+
ok: true
83+
});
84+
85+
const message: JSONRPCMessage = {
86+
jsonrpc: "2.0",
87+
id: "1",
88+
method: "test",
89+
params: {}
90+
};
91+
92+
await transport.send(message);
93+
94+
// Verify fetch was called with correct headers
95+
expect(global.fetch).toHaveBeenCalledWith(
96+
expect.any(URL),
97+
expect.objectContaining({
98+
headers: expect.any(Headers)
99+
})
100+
);
101+
102+
const calledHeaders = (global.fetch as jest.Mock).mock.calls[0][1].headers;
103+
expect(calledHeaders.get("Authorization")).toBe(customHeaders.Authorization);
104+
expect(calledHeaders.get("X-Custom-Header")).toBe(customHeaders["X-Custom-Header"]);
105+
expect(calledHeaders.get("content-type")).toBe("application/json");
106+
});
107+
});

0 commit comments

Comments
 (0)