import { describe, expect, test } from 'bun:test' import { resolve } from 'node:path' import { buildMiniMaxUsageRows, getMiniMaxUsageUrls, normalizeMiniMaxUsagePayload, } from './minimaxUsage.js' const fixture = (name: string) => Bun.file(resolve(import.meta.dir, '__fixtures__', name)) describe('normalizeMiniMaxUsagePayload', () => { test('normalizes interval and weekly quota payloads', () => { const usage = normalizeMiniMaxUsagePayload({ plan_type: 'plus_highspeed', data: { 'MiniMax-M2.7-highspeed': { current_interval_usage_count: 4200, max_interval_usage_count: 4500, current_weekly_usage_count: 43000, max_weekly_usage_count: 45000, }, }, }) expect(usage).toMatchObject({ availability: 'available', planType: 'Plus Highspeed', snapshots: [ { limitName: 'MiniMax-M2.7-highspeed', windows: [ { label: '5h limit', usedPercent: 93, remaining: 300, total: 4500, }, { label: 'Weekly limit', usedPercent: 96, remaining: 2000, total: 45000, }, ], }, ], }) }) test('normalizes daily quota payloads from generic usage records', () => { const usage = normalizeMiniMaxUsagePayload({ models: { image_01: { daily_remaining: 12, daily_quota: 50, }, }, }) expect(usage).toMatchObject({ availability: 'available', snapshots: [ { limitName: 'image_01', windows: [ { label: 'Daily limit', usedPercent: 76, remaining: 12, total: 50, }, ], }, ], }) }) test('normalizes MiniMax model_remains payloads from a captured fixture', async () => { const payload = await fixture('minimax-model-remains.json').json() const originalDateNow = Date.now Date.now = () => Date.parse('2026-02-20T15:00:00.000Z') try { const usage = normalizeMiniMaxUsagePayload(payload) expect(usage).toMatchObject({ availability: 'available', planType: 'Plus Highspeed', snapshots: [ { limitName: 'MiniMax-M2.7', windows: [ { label: '5h limit', usedPercent: 96, remaining: 63, total: 1500, resetsAt: '2026-02-20T16:00:00.000Z', }, ], }, { limitName: 'MiniMax-M2.7-highspeed', windows: [ { label: '5h limit', usedPercent: 50, remaining: 1000, total: 2000, resetsAt: '2026-02-20T16:00:00.000Z', }, ], }, ], }) } finally { Date.now = originalDateNow } }) test('treats current_interval_usage_count as used count for MiniMax subscription payloads', () => { const usage = normalizeMiniMaxUsagePayload({ model_remains: [ { current_interval_total_count: 1500, current_interval_usage_count: 1, model_name: 'MiniMax-M2.7', }, ], }) expect(usage).toMatchObject({ availability: 'available', snapshots: [ { limitName: 'MiniMax-M2.7', windows: [ { label: '5h limit', usedPercent: 0, remaining: 1499, total: 1500, }, ], }, ], }) }) test('treats MiniMax usage_percent as remaining percentage', () => { const usage = normalizeMiniMaxUsagePayload({ model_remains: [ { model_name: 'MiniMax-M2.7-highspeed', usage_percent: 96, }, ], }) expect(usage).toMatchObject({ availability: 'available', snapshots: [ { limitName: 'MiniMax-M2.7-highspeed', windows: [ { label: '5h limit', usedPercent: 4, }, ], }, ], }) }) test('returns unknown availability when no quota windows can be parsed', () => { const usage = normalizeMiniMaxUsagePayload({ message: 'quota status unavailable', ok: true, }) expect(usage).toEqual({ availability: 'unknown', planType: undefined, snapshots: [], message: 'Usage details are not available for this MiniMax account. This plan or MiniMax endpoint may not expose quota status.', }) }) }) describe('buildMiniMaxUsageRows', () => { test('builds provider-prefixed labels and remaining subtext', () => { const rows = buildMiniMaxUsageRows([ { limitName: 'MiniMax-M2.7', windows: [ { label: '5h limit', usedPercent: 20, remaining: 1200, total: 1500, }, { label: 'Weekly limit', usedPercent: 10, remaining: 13500, total: 15000, }, ], }, { limitName: 'image_01', windows: [ { label: 'Daily limit', usedPercent: 76, remaining: 12, total: 50, }, ], }, ]) expect(rows).toEqual([ { kind: 'text', label: 'MiniMax-M2.7 quota', value: '', }, { kind: 'window', label: '5h limit', usedPercent: 20, resetsAt: undefined, extraSubtext: '1200/1500 remaining', }, { kind: 'window', label: 'Weekly limit', usedPercent: 10, resetsAt: undefined, extraSubtext: '13500/15000 remaining', }, { kind: 'window', label: 'Image 01 Daily limit', usedPercent: 76, resetsAt: undefined, extraSubtext: '12/50 remaining', }, ]) }) }) describe('MiniMax usage helpers', () => { test('keeps usage endpoints on the configured provider host and path', () => { expect( getMiniMaxUsageUrls('https://proxy.example/providers/minimax/v1'), ).toEqual([ 'https://proxy.example/providers/minimax/v1/token_plan/remains', 'https://proxy.example/providers/minimax/v1/api/openplatform/coding_plan/remains', ]) }) test('falls back to OPENAI_API_BASE when OPENAI_BASE_URL is unset', () => { const originalBaseUrl = process.env.OPENAI_BASE_URL const originalApiBase = process.env.OPENAI_API_BASE delete process.env.OPENAI_BASE_URL process.env.OPENAI_API_BASE = 'https://gateway.example/openai/v1' try { expect(getMiniMaxUsageUrls()).toEqual([ 'https://gateway.example/openai/v1/token_plan/remains', 'https://gateway.example/openai/v1/api/openplatform/coding_plan/remains', ]) } finally { if (originalBaseUrl === undefined) { delete process.env.OPENAI_BASE_URL } else { process.env.OPENAI_BASE_URL = originalBaseUrl } if (originalApiBase === undefined) { delete process.env.OPENAI_API_BASE } else { process.env.OPENAI_API_BASE = originalApiBase } } }) test('throws when an explicitly configured MiniMax base url is invalid', () => { expect(() => getMiniMaxUsageUrls('not a url')).toThrow( 'MiniMax usage base URL is invalid: not a url', ) }) test('uses the default MiniMax base url when no provider base is configured', () => { const originalBaseUrl = process.env.OPENAI_BASE_URL const originalApiBase = process.env.OPENAI_API_BASE delete process.env.OPENAI_BASE_URL delete process.env.OPENAI_API_BASE try { expect(getMiniMaxUsageUrls()).toEqual([ 'https://api.minimax.io/v1/token_plan/remains', 'https://api.minimax.io/v1/api/openplatform/coding_plan/remains', ]) } finally { if (originalBaseUrl === undefined) { delete process.env.OPENAI_BASE_URL } else { process.env.OPENAI_BASE_URL = originalBaseUrl } if (originalApiBase === undefined) { delete process.env.OPENAI_API_BASE } else { process.env.OPENAI_API_BASE = originalApiBase } } }) })