





















@@ -56,6 +56,16 @@ class TestGatewayPlugin extends GatewayPlugin {
5656}
5757}
585859+type GatewaySessionState = {
60+sessionId: string | null;
61+resumeGatewayUrl: string | null;
62+sequence: number | null;
63+};
64+65+function gatewaySessionState(gateway: GatewayPlugin): GatewaySessionState {
66+return gateway as unknown as GatewaySessionState;
67+}
68+5969describe("GatewayPlugin", () => {
6070afterEach(() => {
6171vi.useRealTimers();
@@ -263,20 +273,71 @@ describe("GatewayPlugin", () => {
263273expect(gateway.sockets).toHaveLength(2);
264274});
265275266-it("re-identifies after non-resumable gateway closes", async () => {
276+it.each([GatewayCloseCodes.InvalidSeq, GatewayCloseCodes.AlreadyAuthenticated])(
277+"re-identifies after non-resumable gateway close %s",
278+async (closeCode) => {
279+vi.useFakeTimers();
280+const gateway = new TestGatewayPlugin({
281+autoInteractions: false,
282+url: "wss://gateway.example.test",
283+});
284+285+gateway.connect(false);
286+gateway.sockets[0]?.emit("open");
287+gateway.sockets[0]?.emit("close", closeCode);
288+await vi.advanceTimersByTimeAsync(2_000);
289+290+expect(gateway.connectCalls).toEqual([false, false]);
291+expect(gateway.sockets).toHaveLength(2);
292+},
293+);
294+295+it("clears resume state after invalid session false", async () => {
267296vi.useFakeTimers();
268297const gateway = new TestGatewayPlugin({
269298autoInteractions: false,
270299url: "wss://gateway.example.test",
271300});
301+const sessionState = gatewaySessionState(gateway);
302+sessionState.sessionId = "session1";
303+sessionState.resumeGatewayUrl = "wss://resume.example.test";
304+sessionState.sequence = 123;
272305273306gateway.connect(false);
274307gateway.sockets[0]?.emit("open");
275-gateway.sockets[0]?.emit("close", GatewayCloseCodes.InvalidSeq);
308+(
309+gateway as unknown as {
310+handlePayload(payload: { op: number; d: unknown }, resume: boolean): void;
311+}
312+).handlePayload({ op: GatewayOpcodes.InvalidSession, d: false }, true);
276313await vi.advanceTimersByTimeAsync(2_000);
277314278315expect(gateway.connectCalls).toEqual([false, false]);
279-expect(gateway.sockets).toHaveLength(2);
316+expect(sessionState.sessionId).toBeNull();
317+expect(sessionState.resumeGatewayUrl).toBeNull();
318+expect(sessionState.sequence).toBeNull();
319+});
320+321+it("includes close code details when reconnect attempts are exhausted", async () => {
322+vi.useFakeTimers();
323+const gateway = new TestGatewayPlugin({
324+autoInteractions: false,
325+reconnect: { maxAttempts: 0 },
326+url: "wss://gateway.example.test",
327+});
328+const errorSpy = vi.fn();
329+gateway.emitter.on("error", errorSpy);
330+331+gateway.connect(false);
332+gateway.sockets[0]?.emit("open");
333+gateway.sockets[0]?.emit("close", 1006);
334+await vi.advanceTimersByTimeAsync(30_000);
335+336+expect(errorSpy).toHaveBeenCalledWith(
337+new Error("Max reconnect attempts (0) reached after close code 1006"),
338+);
339+expect(gateway.connectCalls).toEqual([false]);
340+expect(gateway.sockets).toHaveLength(1);
280341});
281342282343it("does not reconnect after fatal gateway closes", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。