import type { AxiosAdapter, AxiosError, InternalAxiosRequestConfig } from "axios"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; const errorMessage = vi.fn(); vi.mock("element-plus", () => ({ ElMessage: { error: errorMessage, }, })); vi.mock("../router", () => ({ default: { push: vi.fn(), }, })); vi.mock("../utils/auth", () => ({ getToken: vi.fn(() => undefined), })); vi.mock("../store/study", () => ({ useStudyStore: vi.fn(() => ({ clearCurrentStudy: vi.fn(), })), })); vi.mock("../session/sessionManager", () => ({ extendAccessToken: vi.fn(), forceLogout: vi.fn(), LOGOUT_REASON_AUTH_EXPIRED: "auth-expired", })); describe("api axios retry", () => { beforeEach(() => { vi.useFakeTimers(); errorMessage.mockClear(); }); afterEach(() => { vi.useRealTimers(); }); it("retries network failures 10 times at 30 second intervals before showing one error", async () => { const api = (await import("./axios")).default; const adapter = vi.fn(async (config) => { const error = new Error("Network Error") as AxiosError; error.config = config as InternalAxiosRequestConfig; error.isAxiosError = true; return Promise.reject(error); }); const request = api.get("/api/v1/projects", { adapter }).catch((error) => error); await vi.dynamicImportSettled(); expect(adapter).toHaveBeenCalledTimes(1); expect(errorMessage).not.toHaveBeenCalled(); for (let retry = 1; retry < 10; retry += 1) { await vi.advanceTimersByTimeAsync(30000); expect(adapter).toHaveBeenCalledTimes(retry + 1); expect(errorMessage).not.toHaveBeenCalled(); } await vi.advanceTimersByTimeAsync(30000); expect(adapter).toHaveBeenCalledTimes(11); await expect(request).resolves.toMatchObject({ message: "Network Error" }); expect(errorMessage).toHaveBeenCalledTimes(1); }); });