@@ -5,7 +5,12 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
5 | 5 | import type { ResolvedClickClackAccount } from "./types.js"; |
6 | 6 | |
7 | 7 | class FakeSocket extends EventEmitter { |
| 8 | +emitErrorOnClose = false; |
| 9 | + |
8 | 10 | close = vi.fn(() => { |
| 11 | +if (this.emitErrorOnClose) { |
| 12 | +this.emit("error", new Error("socket closed while connecting")); |
| 13 | +} |
9 | 14 | this.emit("close"); |
10 | 15 | }); |
11 | 16 | } |
@@ -191,6 +196,46 @@ describe("ClickClack gateway", () => {
|
191 | 196 | await run; |
192 | 197 | }); |
193 | 198 | |
| 199 | +it("reconnects after ClickClack websocket errors", async () => { |
| 200 | +const firstSocket = new FakeSocket(); |
| 201 | +firstSocket.emitErrorOnClose = true; |
| 202 | +const secondSocket = new FakeSocket(); |
| 203 | +mocks.client.websocket.mockReturnValueOnce(firstSocket).mockReturnValueOnce(secondSocket); |
| 204 | +const abort = new AbortController(); |
| 205 | +const ctx = createGatewayContext(abort.signal); |
| 206 | +const run = startClickClackGatewayAccount(ctx); |
| 207 | + |
| 208 | +await vi.waitFor(() => expect(mocks.client.websocket).toHaveBeenCalledTimes(1)); |
| 209 | + |
| 210 | +firstSocket.emit("error", new Error("gateway dropped")); |
| 211 | + |
| 212 | +await vi.waitFor(() => expect(mocks.client.websocket).toHaveBeenCalledTimes(2)); |
| 213 | +expect(ctx.log?.warn).toHaveBeenCalledWith( |
| 214 | +"[default] ClickClack websocket error; reconnecting: gateway dropped", |
| 215 | +); |
| 216 | +abort.abort(); |
| 217 | +await run; |
| 218 | +}); |
| 219 | + |
| 220 | +it("does not log reconnect warnings when abort closes a connecting websocket", async () => { |
| 221 | +const socket = new FakeSocket(); |
| 222 | +socket.emitErrorOnClose = true; |
| 223 | +mocks.client.websocket.mockReturnValue(socket); |
| 224 | +const abort = new AbortController(); |
| 225 | +const ctx = createGatewayContext(abort.signal); |
| 226 | +const run = startClickClackGatewayAccount(ctx); |
| 227 | + |
| 228 | +await vi.waitFor(() => expect(mocks.client.websocket).toHaveBeenCalledTimes(1)); |
| 229 | + |
| 230 | +abort.abort(); |
| 231 | +await run; |
| 232 | + |
| 233 | +expect(ctx.log?.warn).not.toHaveBeenCalledWith( |
| 234 | +"[default] ClickClack websocket error; reconnecting: socket closed while connecting", |
| 235 | +); |
| 236 | +expect(mocks.client.websocket).toHaveBeenCalledTimes(1); |
| 237 | +}); |
| 238 | + |
194 | 239 | it("clears running status when backlog polling fails", async () => { |
195 | 240 | mocks.client.events.mockRejectedValue(new Error("clickclack unavailable")); |
196 | 241 | const abort = new AbortController(); |
|