| import { describe, it, expect, vi, beforeEach } from "vitest"; |
|
|
| vi.mock("../../open-sse/utils/proxyFetch.js", () => ({ |
| proxyAwareFetch: vi.fn(), |
| })); |
|
|
| import { proxyAwareFetch } from "../../open-sse/utils/proxyFetch.js"; |
| import { getUsageForProvider } from "../../open-sse/services/usage.js"; |
|
|
| function usageResponse(modelRemains) { |
| return new Response( |
| JSON.stringify({ |
| base_resp: { status_code: 0, status_msg: "success" }, |
| model_remains: modelRemains, |
| }), |
| { status: 200, headers: { "Content-Type": "application/json" } } |
| ); |
| } |
|
|
| describe("MiniMax usage", () => { |
| beforeEach(() => { |
| vi.clearAllMocks(); |
| }); |
|
|
| it("parses token-plan TTS quota counts as used counts", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| model_name: "text to speech hd", |
| current_interval_total_count: 4000, |
| current_interval_usage_count: 25, |
| current_weekly_total_count: 12000, |
| current_weekly_usage_count: 100, |
| end_time: "2026-05-12T10:00:00.000Z", |
| weekly_end_time: "2026-05-19T10:00:00.000Z", |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax", |
| apiKey: "test-key", |
| }); |
|
|
| expect(usage.message).toBeUndefined(); |
| expect(usage.quotas["Text to Speech HD (5h)"]).toMatchObject({ |
| used: 25, |
| total: 4000, |
| remaining: 3975, |
| }); |
| expect(usage.quotas["Text to Speech HD (7d)"]).toMatchObject({ |
| used: 100, |
| total: 12000, |
| remaining: 11900, |
| }); |
| }); |
|
|
| it("parses coding-plan TTS quota counts as remaining counts", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| modelName: "Text to Speech HD", |
| currentIntervalTotalCount: 4000, |
| currentIntervalUsageCount: 4000, |
| currentWeeklyTotalCount: 12000, |
| currentWeeklyUsageCount: 11800, |
| remainsTime: 1000, |
| weeklyRemainsTime: 2000, |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax-cn", |
| apiKey: "test-key", |
| }); |
|
|
| expect(usage.message).toBeUndefined(); |
| expect(usage.quotas["Text to Speech HD (5h)"]).toMatchObject({ |
| used: 0, |
| total: 4000, |
| remaining: 4000, |
| }); |
| expect(usage.quotas["Text to Speech HD (7d)"]).toMatchObject({ |
| used: 200, |
| total: 12000, |
| remaining: 11800, |
| }); |
| }); |
|
|
| it("keeps non-TTS MiniMax quota rows instead of filtering to text only", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| model_name: "music-2.6", |
| current_interval_total_count: 100, |
| current_interval_usage_count: 5, |
| }, |
| { |
| model_name: "image-01", |
| current_interval_total_count: 50, |
| current_interval_usage_count: 2, |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax", |
| apiKey: "test-key", |
| }); |
|
|
| expect(Object.keys(usage.quotas)).toEqual(["Music 2.6 (5h)", "Image 01 (5h)"]); |
| expect(usage.quotas["Music 2.6 (5h)"].used).toBe(5); |
| expect(usage.quotas["Image 01 (5h)"].used).toBe(2); |
| }); |
|
|
| it("includes M-series percent-only buckets that have no count totals", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| model_name: "general", |
| current_interval_remaining_percent: 70, |
| current_weekly_remaining_percent: 64, |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax", |
| apiKey: "test-key", |
| }); |
|
|
| expect(usage.message).toBeUndefined(); |
| expect(usage.quotas["M-series (5h)"]).toMatchObject({ |
| used: 30, |
| total: 100, |
| remaining: 70, |
| remainingPercentage: 70, |
| }); |
| expect(usage.quotas["M-series (7d)"]).toMatchObject({ |
| used: 36, |
| total: 100, |
| remaining: 64, |
| remainingPercentage: 64, |
| }); |
| }); |
|
|
| it("normalizes M-series percent-only buckets on the coding_plan (countMeansRemaining) endpoint too", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| model_name: "general", |
| current_interval_remaining_percent: 80, |
| current_weekly_remaining_percent: 95, |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax-cn", |
| apiKey: "test-key", |
| }); |
|
|
| expect(usage.message).toBeUndefined(); |
| expect(usage.quotas["M-series (5h)"]).toMatchObject({ |
| used: 20, |
| total: 100, |
| remaining: 80, |
| remainingPercentage: 80, |
| }); |
| expect(usage.quotas["M-series (7d)"]).toMatchObject({ |
| used: 5, |
| total: 100, |
| remaining: 95, |
| remainingPercentage: 95, |
| }); |
| }); |
|
|
| it("renders the M3-era MiniMax-M* wildcard as a friendly series label", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| modelName: "MiniMax-M*", |
| currentIntervalTotalCount: 4000, |
| currentIntervalUsageCount: 3200, |
| currentWeeklyTotalCount: 24000, |
| currentWeeklyUsageCount: 18000, |
| remainsTime: 1000, |
| weeklyRemainsTime: 2000, |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax-cn", |
| apiKey: "test-key", |
| }); |
|
|
| expect(usage.message).toBeUndefined(); |
| expect(Object.keys(usage.quotas)).toEqual([ |
| "M-series (5h)", |
| "M-series (7d)", |
| ]); |
| expect(usage.quotas["M-series (5h)"]).toMatchObject({ |
| used: 800, |
| total: 4000, |
| remaining: 3200, |
| }); |
| expect(usage.quotas["M-series (7d)"]).toMatchObject({ |
| used: 6000, |
| total: 24000, |
| remaining: 18000, |
| }); |
| }); |
|
|
| it("prefers the upstream-provided remaining percent when counts are also present", async () => { |
| proxyAwareFetch.mockResolvedValueOnce( |
| usageResponse([ |
| { |
| model_name: "general", |
| current_interval_total_count: 4000, |
| current_interval_usage_count: 100, |
| current_interval_remaining_percent: 84, |
| current_weekly_total_count: 24000, |
| current_weekly_usage_count: 500, |
| current_weekly_remaining_percent: 42, |
| }, |
| ]) |
| ); |
|
|
| const usage = await getUsageForProvider({ |
| provider: "minimax", |
| apiKey: "test-key", |
| }); |
|
|
| expect(usage.quotas["M-series (5h)"].remainingPercentage).toBe(84); |
| expect(usage.quotas["M-series (7d)"].remainingPercentage).toBe(42); |
| }); |
| }); |
|
|