-
Notifications
You must be signed in to change notification settings - Fork 212
Expand file tree
/
Copy pathcallbackServer.spec.ts
More file actions
137 lines (114 loc) · 3.8 KB
/
Copy pathcallbackServer.spec.ts
File metadata and controls
137 lines (114 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import { describe, it, expect, vi, beforeEach } from "vitest"
import { startCallbackServer, stopCallbackServer } from "../callbackServer"
import * as http from "http"
vi.mock("http", () => ({
createServer: vi.fn(),
}))
function createMockServer() {
const mockServer = {
listen: vi.fn((port, host, callback) => {
callback()
return mockServer
}),
address: vi.fn(() => ({ port: 3000 })),
on: vi.fn(),
close: vi.fn(),
}
return mockServer
}
function createMockResponse() {
return {
writeHead: vi.fn(),
end: vi.fn(),
on: vi.fn((event, cb) => {
if (event === "finish") setImmediate(cb)
}),
}
}
describe("startCallbackServer", () => {
beforeEach(() => {
vi.restoreAllMocks()
delete process.env.MCP_OAUTH_TEST_MODE
})
it("should start server and resolve with callback result", async () => {
const mockServer = createMockServer()
;(http.createServer as any).mockReturnValue(mockServer)
const promise = startCallbackServer()
const { server, port, result } = await promise
expect(port).toBe(3000)
expect(server).toBe(mockServer)
// Simulate callback request
const requestCall = mockServer.on.mock.calls.find((call) => call[0] === "request")
const requestHandler = requestCall ? requestCall[1] : vi.fn()
const mockReq = {
url: "/callback?code=test-code&state=test-state",
method: "GET",
}
const mockRes = createMockResponse()
requestHandler(mockReq, mockRes)
const callbackResult = await result
expect(callbackResult.code).toBe("test-code")
expect(callbackResult.state).toBe("test-state")
expect(mockRes.writeHead).toHaveBeenCalledWith(
200,
expect.objectContaining({
"Content-Type": "text/html; charset=utf-8",
}),
)
expect(mockRes.end).toHaveBeenCalledWith(expect.stringContaining('<meta charset="utf-8">'))
})
it("should reject invalid state", async () => {
const mockServer = createMockServer()
;(http.createServer as any).mockReturnValue(mockServer)
const promise = startCallbackServer(undefined, "expected-state")
const { result } = await promise
// Simulate callback request with wrong state
const requestCall = mockServer.on.mock.calls.find((call) => call[0] === "request")
const requestHandler = requestCall ? requestCall[1] : vi.fn()
const mockReq = {
url: "/callback?code=test-code&state=wrong-state",
method: "GET",
}
const mockRes = createMockResponse()
requestHandler(mockReq, mockRes)
await expect(result).rejects.toThrow("Invalid state parameter")
expect(mockRes.writeHead).toHaveBeenCalledWith(
400,
expect.objectContaining({
"Content-Type": "text/html; charset=utf-8",
}),
)
expect(mockRes.end).toHaveBeenCalledWith(expect.stringContaining('<meta charset="utf-8">'))
})
})
describe("stopCallbackServer", () => {
it("should close the server", async () => {
const mockServer = {
close: vi.fn((callback) => callback()),
}
await stopCallbackServer(mockServer as any, () => {})
expect(mockServer.close).toHaveBeenCalled()
})
it("should call the cancel function before closing", async () => {
const mockServer = { close: vi.fn((callback) => callback()) }
const cancel = vi.fn()
await stopCallbackServer(mockServer as any, cancel)
expect(cancel).toHaveBeenCalledTimes(1)
expect(mockServer.close).toHaveBeenCalled()
})
})
describe("startCallbackServer in test mode", () => {
it("should resolve immediately with mock auth code when MCP_OAUTH_TEST_MODE is set", async () => {
process.env.MCP_OAUTH_TEST_MODE = "true"
try {
const { port, result, cancel } = await startCallbackServer(undefined, "test-state")
expect(port).toBe(3000)
expect(typeof cancel).toBe("function")
const callbackResult = await result
expect(callbackResult.code).toBe("test-auth-code")
expect(callbackResult.state).toBe("test-state")
} finally {
delete process.env.MCP_OAUTH_TEST_MODE
}
})
})