diff --git a/__tests__/index/retryConnectionDelay.test.ts b/__tests__/index/retryConnectionDelay.test.ts index f343342..c8c5cbe 100644 --- a/__tests__/index/retryConnectionDelay.test.ts +++ b/__tests__/index/retryConnectionDelay.test.ts @@ -68,71 +68,74 @@ describe("Exponential backoff delay", () => { describe("with rate 2, backoffLimit 8000 ms", () => { // The initial delay shall be 1 s const initialDelay = 1000; - const exponentialBackoffParams: ExponentialBackoffParams = { + const exponentialBackoff: ExponentialBackoffParams = { backoffRate: 2, // We put the ceiling at exactly 8000 ms backoffLimit: 8000, }; + const attempts: [number, number][] = [ + [1000, 0], + [2000, 1], + [4000, 2], + [8000, 3], + [8000, 4], + ]; it("will never be more than 8000 ms with rate set to 2", () => { - expect( - calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 0), - ).toBe(1000); - expect( - calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 1), - ).toBe(2000); - expect( - calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 2), - ).toBe(4000); - expect( - calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 3), - ).toBe(8000); - expect( - calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 4), - ).toBe(8000); + attempts.forEach(([delay, failedAttempts]) => { + expect( + calculateRetryDelayFactor( + exponentialBackoff, + initialDelay, + failedAttempts, + ), + ).toBe(delay); + }); }); it("should delay reconnection attempts exponentially", async () => { + // Somehow we need to convincen typescript here that "WebSocket" is + // totally valid. Could be because it doesn't assume WebSocket is part of + // global / the index key is missing const webSocketSpy = jest.spyOn(global, "WebSocket" as any); webSocketSpy.mockImplementation(() => {}); const setTimeoutSpy = jest.spyOn(global, "setTimeout"); - const sarus = new Sarus({ - url, - exponentialBackoff: exponentialBackoffParams, - }); + const sarus = new Sarus({ url, exponentialBackoff }); expect(sarus.state).toStrictEqual({ kind: "connecting", failedConnectionAttempts: 0, }); let instance: WebSocket; + // Get the first WebSocket instance, and ... [instance] = webSocketSpy.mock.instances; if (!instance.onopen) { throw new Error(); } + // tell the sarus instance that it is open, and ... instance.onopen(new Event("open")); if (!instance.onclose) { throw new Error(); } + // close it immediately instance.onclose(new CloseEvent("close")); + expect(sarus.state).toStrictEqual({ + kind: "closed", + failedConnectionAttempts: 0, + }); let cb: Sarus["connect"]; // We iteratively call sarus.connect() and let it fail, seeing // if it reaches 8000 as a delay and stays there - const attempts: [number, number][] = [ - [1000, 1], - [2000, 2], - [4000, 3], - [8000, 4], - [8000, 5], - ]; - attempts.forEach(([delay, failedAttempts]: [number, number]) => { + attempts.forEach(([delay, failedAttempts]) => { const call = setTimeoutSpy.mock.calls[setTimeoutSpy.mock.calls.length - 1]; if (!call) { throw new Error(); } + // Make sure that setTimeout was called with the correct delay expect(call[1]).toBe(delay); cb = call[0]; cb(); + // Get the most recent WebSocket instance instance = webSocketSpy.mock.instances[webSocketSpy.mock.instances.length - 1]; if (!instance.onclose) { @@ -141,7 +144,7 @@ describe("Exponential backoff delay", () => { instance.onclose(new CloseEvent("close")); expect(sarus.state).toStrictEqual({ kind: "connecting", - failedConnectionAttempts: failedAttempts, + failedConnectionAttempts: failedAttempts + 1, }); }); });