Files
orcs-code/src/services/api/minimaxUsage.test.ts
JATMN 26413f6d30 feat(minimax): add /usage support and fix MiniMax quota parsing (#869)
* Add MiniMax usage UI and API support

* Fix MiniMax usage parsing and refresh UI

* Refactor MiniMax usage handling
2026-04-25 12:33:22 +08:00

326 lines
8.3 KiB
TypeScript

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
}
}
})
})