import { describe, expect, it } from "vitest"; import { createProviderUsageFetch, makeResponse } from "../test-utils/provider-usage-fetch.js"; import { fetchMinimaxUsage } from "./provider-usage.fetch.minimax.js"; async function expectMinimaxUsageResult(params: { payload: unknown; expected: { plan?: string; windows: Array<{ label: string; usedPercent: number; resetAt?: number }>; }; }) { const mockFetch = createProviderUsageFetch(async (_url, init) => { const headers = (init?.headers as Record | undefined) ?? {}; expect(headers.Authorization).toBe("Bearer key"); expect(headers["MM-API-Source"]).toBe("OpenClaw"); return makeResponse(200, params.payload); }); const result = await fetchMinimaxUsage("key", 5000, mockFetch); expect(result.plan).toBe(params.expected.plan); expect(result.windows).toEqual(params.expected.windows); } describe("fetchMinimaxUsage", () => { it.each([ { name: "returns HTTP errors for failed requests", response: () => makeResponse(502, "bad gateway"), expectedError: "HTTP 502", }, { name: "returns invalid JSON when payload cannot be parsed", response: () => makeResponse(200, "{not-json"), expectedError: "Invalid JSON", }, { name: "returns trimmed API errors from base_resp", response: () => makeResponse(200, { base_resp: { status_code: 1007, status_msg: " auth denied ", }, }), expectedError: "auth denied", }, { name: "falls back to a generic API error when base_resp message is blank", response: () => makeResponse(200, { base_resp: { status_code: 1007, status_msg: " ", }, }), expectedError: "API error", }, ])("$name", async ({ response, expectedError }) => { const mockFetch = createProviderUsageFetch(async () => response()); const result = await fetchMinimaxUsage("key", 5000, mockFetch); expect(result.error).toBe(expectedError); expect(result.windows).toHaveLength(0); }); it.each([ { name: "derives usage from used/total fields and includes reset + plan", payload: { data: { used: 35, total: 100, window_hours: 3, reset_at: 1_700_000_000, plan_name: "Pro Max", }, }, expected: { plan: "Pro Max", windows: [{ label: "3h", usedPercent: 35, resetAt: 1_700_000_000_000 }], }, }, { name: "supports usage ratio strings with minute windows and ISO reset strings", payload: { data: { nested: [ { usage_ratio: "0.25", window_minutes: "30", reset_time: "2026-01-08T00:00:00Z", plan: "Starter", }, ], }, }, expected: { plan: "Starter", windows: [ { label: "30m", usedPercent: 25, resetAt: new Date("2026-01-08T00:00:00Z").getTime() }, ], }, }, { name: "derives used from total and remaining counts", payload: { data: { total: "200", remaining: "50", usage_percent: 75, reset_at: 1_700_000_000_000, plan_name: "Team", }, }, expected: { plan: "Team", windows: [{ label: "5h", usedPercent: 75, resetAt: 1_700_000_000_000 }], }, }, { name: "falls back to payload-level reset and plan when nested usage records omit them", payload: { data: { plan_name: "Payload Plan", reset_at: 1_700_000_100, nested: [{ usage_ratio: 0.4, window_hours: 2 }], }, }, expected: { plan: "Payload Plan", windows: [{ label: "2h", usedPercent: 40, resetAt: 1_700_000_100_000 }], }, }, ])("$name", async ({ payload, expected }) => { await expectMinimaxUsageResult({ payload, expected }); }); it("returns unsupported response shape when no usage fields are present", async () => { const mockFetch = createProviderUsageFetch(async () => makeResponse(200, { data: { foo: "bar" } }), ); const result = await fetchMinimaxUsage("key", 5000, mockFetch); expect(result.error).toBe("Unsupported response shape"); expect(result.windows).toHaveLength(0); }); it("handles repeated nested records while scanning usage candidates", async () => { const sharedUsage = { total: 100, used: 20, usage_percent: 90, window_hours: 1, }; const dataWithSharedReference = { first: sharedUsage, nested: [sharedUsage], }; const mockFetch = createProviderUsageFetch( async () => ({ ok: true, status: 200, json: async () => ({ data: dataWithSharedReference }), }) as Response, ); const result = await fetchMinimaxUsage("key", 5000, mockFetch); expect(result.windows).toEqual([{ label: "1h", usedPercent: 20, resetAt: undefined }]); }); });