



























11import { EventEmitter } from "node:events";
2+import { DisconnectReason } from "baileys";
23import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
34import { getRegisteredWhatsAppConnectionController } from "./connection-controller-registry.js";
4-import { closeWaSocket, WhatsAppConnectionController } from "./connection-controller.js";
5+import {
6+closeWaSocket,
7+waitForWhatsAppLoginResult,
8+WhatsAppConnectionController,
9+} from "./connection-controller.js";
510import type { WhatsAppSendKind, WhatsAppSendResult } from "./inbound/send-result.js";
611import { createWaSocket, waitForWaConnection } from "./session.js";
712@@ -127,6 +132,120 @@ describe("WhatsAppConnectionController", () => {
127132expect(callOrder).toEqual(["create", "wait-for-connection"]);
128133});
129134135+it("restarts login once on status 408 and preserves replacement socket options", async () => {
136+const initialSock = createSocketWithTransportEmitter();
137+const replacementSock = createSocketWithTransportEmitter();
138+const waitForConnection = vi
139+.fn()
140+.mockRejectedValueOnce({ output: { statusCode: DisconnectReason.timedOut } })
141+.mockResolvedValueOnce(undefined);
142+const onQr = vi.fn();
143+const onSocketReplaced = vi.fn();
144+const createSocket = vi.fn(
145+async (_printQr: boolean, _verbose: boolean, opts?: { onQr?: (qr: string) => void }) => {
146+opts?.onQr?.("qr-after-timeout");
147+return replacementSock;
148+},
149+);
150+151+const result = await waitForWhatsAppLoginResult({
152+sock: initialSock as never,
153+authDir: "/tmp/wa-auth",
154+isLegacyAuthDir: false,
155+verbose: true,
156+runtime: { log: vi.fn() } as never,
157+waitForConnection: waitForConnection as never,
158+createSocket: createSocket as never,
159+socketTiming: {
160+connectTimeoutMs: 10_000,
161+defaultQueryTimeoutMs: 20_000,
162+keepAliveIntervalMs: 30_000,
163+},
164+ onQr,
165+ onSocketReplaced,
166+});
167+168+expect(result).toEqual({
169+outcome: "connected",
170+restarted: true,
171+sock: replacementSock,
172+});
173+expect(initialSock.end).toHaveBeenCalledOnce();
174+expect(createSocket).toHaveBeenCalledWith(false, true, {
175+authDir: "/tmp/wa-auth",
176+connectTimeoutMs: 10_000,
177+defaultQueryTimeoutMs: 20_000,
178+keepAliveIntervalMs: 30_000,
179+ onQr,
180+});
181+expect(onQr).toHaveBeenCalledWith("qr-after-timeout");
182+expect(onSocketReplaced).toHaveBeenCalledWith(replacementSock);
183+});
184+185+it("still honors the post-pairing 515 restart after a status 408 recovery", async () => {
186+const initialSock = createSocketWithTransportEmitter();
187+const afterTimeoutSock = createSocketWithTransportEmitter();
188+const afterPairingRestartSock = createSocketWithTransportEmitter();
189+const waitForConnection = vi
190+.fn()
191+.mockRejectedValueOnce({ output: { statusCode: DisconnectReason.timedOut } })
192+.mockRejectedValueOnce({ output: { statusCode: 515 } })
193+.mockResolvedValueOnce(undefined);
194+const createSocket = vi
195+.fn()
196+.mockResolvedValueOnce(afterTimeoutSock)
197+.mockResolvedValueOnce(afterPairingRestartSock);
198+199+const result = await waitForWhatsAppLoginResult({
200+sock: initialSock as never,
201+authDir: "/tmp/wa-auth",
202+isLegacyAuthDir: false,
203+verbose: false,
204+runtime: { log: vi.fn() } as never,
205+waitForConnection: waitForConnection as never,
206+createSocket: createSocket as never,
207+});
208+209+expect(result).toEqual({
210+outcome: "connected",
211+restarted: true,
212+sock: afterPairingRestartSock,
213+});
214+expect(createSocket).toHaveBeenCalledTimes(2);
215+expect(waitForConnection).toHaveBeenCalledTimes(3);
216+expect(initialSock.end).toHaveBeenCalledOnce();
217+expect(afterTimeoutSock.end).toHaveBeenCalledOnce();
218+});
219+220+it("does not keep recreating sockets when login status 408 persists", async () => {
221+const initialSock = createSocketWithTransportEmitter();
222+const replacementSock = createSocketWithTransportEmitter();
223+const timeoutError = { output: { statusCode: DisconnectReason.timedOut } };
224+const waitForConnection = vi
225+.fn()
226+.mockRejectedValueOnce(timeoutError)
227+.mockRejectedValueOnce(timeoutError);
228+const createSocket = vi.fn(async () => replacementSock);
229+230+const result = await waitForWhatsAppLoginResult({
231+sock: initialSock as never,
232+authDir: "/tmp/wa-auth",
233+isLegacyAuthDir: false,
234+verbose: false,
235+runtime: { log: vi.fn() } as never,
236+waitForConnection: waitForConnection as never,
237+createSocket: createSocket as never,
238+});
239+240+expect(result).toMatchObject({
241+outcome: "failed",
242+statusCode: DisconnectReason.timedOut,
243+error: timeoutError,
244+});
245+expect(createSocket).toHaveBeenCalledOnce();
246+expect(waitForConnection).toHaveBeenCalledTimes(2);
247+});
248+130249it("keeps the previous registered controller until a replacement listener is ready", async () => {
131250const liveController = new WhatsAppConnectionController({
132251accountId: "work",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。