
























@@ -37,6 +37,18 @@ function createWsClient(): MockWsClient {
3737};
3838}
393940+function firstRuntimeError(runtime: { error: ReturnType<typeof vi.fn> }): string {
41+return String(runtime.error.mock.calls.at(0)?.at(0) ?? "");
42+}
43+44+function firstWsCallbacks(): { onError?: (err: Error) => void } {
45+const callbacks = createFeishuWSClientMock.mock.calls.at(0)?.at(1);
46+if (!callbacks || typeof callbacks !== "object") {
47+throw new Error("expected Feishu websocket callbacks");
48+}
49+return callbacks as { onError?: (err: Error) => void };
50+}
51+4052afterEach(() => {
4153vi.useRealTimers();
4254stopFeishuMonitorState();
@@ -131,7 +143,7 @@ describe("feishu websocket cleanup", () => {
131143expect(createFeishuWSClientMock).toHaveBeenCalledTimes(2);
132144expect(recoveredClient.close).toHaveBeenCalledTimes(1);
133145expect(runtime.error).toHaveBeenCalledTimes(1);
134-const errorMessage = String(runtime.error.mock.calls[0]?.[0] ?? "");
146+const errorMessage = firstRuntimeError(runtime);
135147expect(errorMessage).toContain("WebSocket start failed, retrying in 1000ms");
136148expect(errorMessage).not.toContain("\n");
137149expect(errorMessage).not.toContain("token_abc");
@@ -171,10 +183,7 @@ describe("feishu websocket cleanup", () => {
171183expect(wsClients.get(accountId)).toBe(exhaustedClient);
172184});
173185174-const callbacks = createFeishuWSClientMock.mock.calls[0]?.[1] as
175-| { onError?: (err: Error) => void }
176-| undefined;
177-callbacks?.onError?.(
186+firstWsCallbacks().onError?.(
178187new Error("WebSocket reconnect exhausted after 3 attempts\nBearer token_abc"),
179188);
180189@@ -199,7 +208,7 @@ describe("feishu websocket cleanup", () => {
199208expect(recoveredClient.close).toHaveBeenCalledTimes(1);
200209expect(botOpenIds.has(accountId)).toBe(false);
201210expect(botNames.has(accountId)).toBe(false);
202-const errorMessage = String(runtime.error.mock.calls[0]?.[0] ?? "");
211+const errorMessage = firstRuntimeError(runtime);
203212expect(errorMessage).toContain("WebSocket connection ended, recreating client in 1000ms");
204213expect(errorMessage).toContain("Bearer [redacted]");
205214expect(errorMessage).not.toContain("\n");
@@ -232,17 +241,14 @@ describe("feishu websocket cleanup", () => {
232241expect(wsClients.get(accountId)).toBe(wsClient);
233242});
234243235-const callbacks = createFeishuWSClientMock.mock.calls[0]?.[1] as
236-| { onError?: (err: Error) => void }
237-| undefined;
238-callbacks?.onError?.(new Error("temporary callback failure\nBearer token_abc"));
244+firstWsCallbacks().onError?.(new Error("temporary callback failure\nBearer token_abc"));
239245240246await vi.advanceTimersByTimeAsync(1_000);
241247242248expect(createFeishuWSClientMock).toHaveBeenCalledTimes(1);
243249expect(wsClient.close).not.toHaveBeenCalled();
244250expect(wsClients.get(accountId)).toBe(wsClient);
245-const errorMessage = String(runtime.error.mock.calls[0]?.[0] ?? "");
251+const errorMessage = firstRuntimeError(runtime);
246252expect(errorMessage).toContain("WebSocket SDK reported recoverable error");
247253expect(errorMessage).toContain("Bearer [redacted]");
248254expect(errorMessage).not.toContain("\n");
@@ -281,10 +287,7 @@ describe("feishu websocket cleanup", () => {
281287expect(exhaustedClient.start).toHaveBeenCalledTimes(1);
282288});
283289284-const callbacks = createFeishuWSClientMock.mock.calls[0]?.[1] as
285-| { onError?: (err: Error) => void }
286-| undefined;
287-callbacks?.onError?.(new Error("WebSocket reconnect exhausted after 3 attempts"));
290+firstWsCallbacks().onError?.(new Error("WebSocket reconnect exhausted after 3 attempts"));
288291289292await vi.waitFor(() => {
290293expect(exhaustedClient.close).toHaveBeenCalledTimes(1);
@@ -328,7 +331,7 @@ describe("feishu websocket cleanup", () => {
328331abortController.abort();
329332await monitorPromise;
330333331-const errorMessage = String(runtime.error.mock.calls[0]?.[0] ?? "");
334+const errorMessage = firstRuntimeError(runtime);
332335expect(errorMessage).toContain("error closing WebSocket client");
333336expect(errorMessage).toContain("access_token=[redacted]");
334337expect(errorMessage).not.toContain("\n");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。