diff --git a/src/telegram/probe.test.ts b/src/telegram/probe.test.ts index edef2a803..11b0b317e 100644 --- a/src/telegram/probe.test.ts +++ b/src/telegram/probe.test.ts @@ -1,13 +1,18 @@ -import { type Mock, describe, expect, it, vi, beforeEach, afterEach } from "vitest"; +import { type Mock, describe, expect, it, vi } from "vitest"; import { withFetchPreconnect } from "../test-utils/fetch-mock.js"; import { probeTelegram } from "./probe.js"; describe("probeTelegram retry logic", () => { const token = "test-token"; const timeoutMs = 5000; - let fetchMock: Mock; - function mockGetMeSuccess() { + const installFetchMock = (): Mock => { + const fetchMock = vi.fn(); + global.fetch = withFetchPreconnect(fetchMock); + return fetchMock; + }; + + function mockGetMeSuccess(fetchMock: Mock) { fetchMock.mockResolvedValueOnce({ ok: true, json: vi.fn().mockResolvedValue({ @@ -17,14 +22,14 @@ describe("probeTelegram retry logic", () => { }); } - function mockGetWebhookInfoSuccess() { + function mockGetWebhookInfoSuccess(fetchMock: Mock) { fetchMock.mockResolvedValueOnce({ ok: true, json: vi.fn().mockResolvedValue({ ok: true, result: { url: "" } }), }); } - async function expectSuccessfulProbe(expectedCalls: number, retryCount = 0) { + async function expectSuccessfulProbe(fetchMock: Mock, expectedCalls: number, retryCount = 0) { const probePromise = probeTelegram(token, timeoutMs); if (retryCount > 0) { await vi.advanceTimersByTimeAsync(retryCount * 1000); @@ -36,17 +41,6 @@ describe("probeTelegram retry logic", () => { expect(result.bot?.username).toBe("test_bot"); } - beforeEach(() => { - vi.useFakeTimers(); - fetchMock = vi.fn(); - global.fetch = withFetchPreconnect(fetchMock); - }); - - afterEach(() => { - vi.useRealTimers(); - vi.restoreAllMocks(); - }); - it.each([ { errors: [], @@ -64,32 +58,45 @@ describe("probeTelegram retry logic", () => { retryCount: 2, }, ])("succeeds after retry pattern %#", async ({ errors, expectedCalls, retryCount }) => { - for (const message of errors) { - fetchMock.mockRejectedValueOnce(new Error(message)); - } + const fetchMock = installFetchMock(); + vi.useFakeTimers(); + try { + for (const message of errors) { + fetchMock.mockRejectedValueOnce(new Error(message)); + } - mockGetMeSuccess(); - mockGetWebhookInfoSuccess(); - await expectSuccessfulProbe(expectedCalls, retryCount); + mockGetMeSuccess(fetchMock); + mockGetWebhookInfoSuccess(fetchMock); + await expectSuccessfulProbe(fetchMock, expectedCalls, retryCount); + } finally { + vi.useRealTimers(); + } }); it("should fail after 3 unsuccessful attempts", async () => { + const fetchMock = installFetchMock(); + vi.useFakeTimers(); const errorMsg = "Final network error"; - fetchMock.mockRejectedValue(new Error(errorMsg)); + try { + fetchMock.mockRejectedValue(new Error(errorMsg)); - const probePromise = probeTelegram(token, timeoutMs); + const probePromise = probeTelegram(token, timeoutMs); - // Fast-forward for all retries - await vi.advanceTimersByTimeAsync(2000); + // Fast-forward for all retries + await vi.advanceTimersByTimeAsync(2000); - const result = await probePromise; + const result = await probePromise; - expect(result.ok).toBe(false); - expect(result.error).toBe(errorMsg); - expect(fetchMock).toHaveBeenCalledTimes(3); // 3 attempts at getMe + expect(result.ok).toBe(false); + expect(result.error).toBe(errorMsg); + expect(fetchMock).toHaveBeenCalledTimes(3); // 3 attempts at getMe + } finally { + vi.useRealTimers(); + } }); it("should NOT retry if getMe returns a 401 Unauthorized", async () => { + const fetchMock = installFetchMock(); const mockResponse = { ok: false, status: 401,