import { describe, expect, test } from 'bun:test' import { buildCodexUsageRows, formatCodexPlanType, getCodexUsageUrl, normalizeCodexUsagePayload, } from './codexUsage.js' describe('normalizeCodexUsagePayload', () => { test('normalizes live Codex usage payloads from /backend-api/wham/usage', () => { const usage = normalizeCodexUsagePayload({ plan_type: 'plus', rate_limit: { primary_window: { used_percent: 38, limit_window_seconds: 18_000, reset_at: 1_775_154_358, }, secondary_window: { used_percent: 32, limit_window_seconds: 604_800, reset_at: 1_775_685_041, }, }, code_review_rate_limit: { primary_window: { used_percent: 0, limit_window_seconds: 604_800, reset_at: 1_775_744_471, }, secondary_window: null, }, credits: { has_credits: false, unlimited: false, balance: '0', }, }) expect(usage.planType).toBe('plus') expect(usage.snapshots).toHaveLength(2) expect(usage.snapshots[0]).toMatchObject({ limitName: 'codex', primary: { usedPercent: 38, windowMinutes: 300, }, secondary: { usedPercent: 32, windowMinutes: 10_080, }, }) expect(usage.snapshots[1]).toMatchObject({ limitName: 'code review', primary: { usedPercent: 0, windowMinutes: 10_080, }, }) }) test('supports direct protocol-style snapshot collections', () => { const usage = normalizeCodexUsagePayload({ rateLimitsByLimitId: { codex: { limit_name: 'codex', primary: { used_percent: 12, window_minutes: 300, resets_at: 1_700_000_000, }, credits: { has_credits: true, unlimited: false, balance: '25', }, }, }, }) expect(usage.snapshots).toEqual([ { limitName: 'codex', primary: { usedPercent: 12, windowMinutes: 300, resetsAt: new Date(1_700_000_000 * 1000).toISOString(), }, secondary: undefined, credits: { hasCredits: true, unlimited: false, balance: '25', }, }, ]) }) }) describe('buildCodexUsageRows', () => { test('builds Codex-like labels for primary and secondary windows', () => { const rows = buildCodexUsageRows([ { limitName: 'codex', primary: { usedPercent: 38, windowMinutes: 300, resetsAt: '2026-04-02T10:00:00.000Z', }, secondary: { usedPercent: 32, windowMinutes: 10_080, resetsAt: '2026-04-09T10:00:00.000Z', }, }, { limitName: 'code review', primary: { usedPercent: 0, windowMinutes: 10_080, resetsAt: '2026-04-09T10:00:00.000Z', }, }, ]) expect(rows).toEqual([ { kind: 'window', label: '5h limit', usedPercent: 38, resetsAt: '2026-04-02T10:00:00.000Z', }, { kind: 'window', label: 'Weekly limit', usedPercent: 32, resetsAt: '2026-04-09T10:00:00.000Z', }, { kind: 'window', label: 'Code review Weekly limit', usedPercent: 0, resetsAt: '2026-04-09T10:00:00.000Z', }, ]) }) test('renders credits rows only when credits are available', () => { const rows = buildCodexUsageRows([ { limitName: 'codex', credits: { hasCredits: true, unlimited: false, balance: '25.2', }, }, { limitName: 'code review', credits: { hasCredits: true, unlimited: true, }, }, { limitName: 'other', credits: { hasCredits: true, unlimited: false, balance: '0', }, }, ]) expect(rows).toEqual([ { kind: 'text', label: 'Credits', value: '25 credits', }, { kind: 'text', label: 'Code review limit', value: '', }, { kind: 'text', label: 'Credits', value: 'Unlimited', }, ]) }) }) describe('Codex usage helpers', () => { test('formats plan labels and usage endpoint url', () => { expect(formatCodexPlanType('team_max')).toBe('Team Max') expect(getCodexUsageUrl()).toBe('https://chatgpt.com/backend-api/wham/usage') expect(getCodexUsageUrl('https://chatgpt.com/backend-api/codex')).toBe( 'https://chatgpt.com/backend-api/wham/usage', ) }) })