import { describe, expect, it, vi } from "vitest"; import { isReadFailureExhausted, readRetry } from "./read-failure"; const transient = { code: "TBANK_UNAVAILABLE", status: 503 }; const settled = { isError: true, isFetching: false }; describe("isReadFailureExhausted", () => { it("is true for a settled transient failure, even without a code", () => { expect(isReadFailureExhausted({ ...settled, error: transient })).toBe(true); expect( isReadFailureExhausted({ ...settled, error: new TypeError("Network request failed"), }), ).toBe(true); }); it("stays true while a manual retry runs and false without a failure", () => { expect( isReadFailureExhausted({ error: transient, isError: true, isFetching: true, }), ).toBe(true); expect( isReadFailureExhausted({ error: null, isError: false, isFetching: false, }), ).toBe(false); }); it.each([ "INVALID_TBANK_TOKEN", "NOT_FOUND", "TBANK_NOT_CONNECTED", "UNAUTHORIZED", ])("is false for %s, which has its own action", (code) => { expect(isReadFailureExhausted({ ...settled, error: { code } })).toBe(false); }); }); describe("readRetry", () => { it("refetches only the failed reads and reports a running retry", () => { const failedRefetch = vi.fn(() => Promise.resolve()); const healthyRefetch = vi.fn(() => Promise.resolve()); const retry = readRetry([ { ...settled, error: transient, refetch: failedRefetch }, { error: null, isError: false, isFetching: true, refetch: healthyRefetch, }, { ...settled, error: { code: "NOT_FOUND" }, refetch: healthyRefetch }, ]); expect(retry).toMatchObject({ exhausted: true, retrying: false }); retry.onRetry(); expect(failedRefetch).toHaveBeenCalledOnce(); expect(healthyRefetch).not.toHaveBeenCalled(); }); it("is not exhausted while every read is healthy", () => { expect( readRetry([ { error: null, isError: false, isFetching: false, refetch: vi.fn(() => Promise.resolve()), }, ]).exhausted, ).toBe(false); }); });