diff --git a/src/components/QuotaActionFeedback.tsx b/src/components/QuotaActionFeedback.tsx index 6f9e67e..8c55dfb 100644 --- a/src/components/QuotaActionFeedback.tsx +++ b/src/components/QuotaActionFeedback.tsx @@ -7,9 +7,7 @@ export function QuotaActionFeedback({ quota }: { quota: QuotaState }) { const result = quota.actionResult; if (!result) return null; const successful = result.status === 'success'; - const message = result.action === 'probe' - ? t(successful ? 'quota.probe.success' : 'quota.probe.failed', { error: result.error ?? '' }) - : t(successful ? 'quota.resetResult.submitted' : result.status === 'refresh-error' + const message = t(successful ? 'quota.resetResult.submitted' : result.status === 'refresh-error' ? 'quota.resetResult.refreshFailed' : 'quota.resetResult.failed', { error: result.error ?? '' }); return (
diff --git a/src/i18n/ja.ts b/src/i18n/ja.ts index 32502bd..19dd79c 100644 --- a/src/i18n/ja.ts +++ b/src/i18n/ja.ts @@ -186,16 +186,8 @@ export const jaOverrides = { 'quota.empty.description': 'まず認証ファイルにクォータ照会対応の認証情報を追加してください。', 'quota.unknownProvider': '不明', 'common.confirm': '確認', - 'quota.probe.button': '利用可否をテスト', - 'quota.probe.title': 'xAI 有料 API のテスト', - 'quota.probe.confirm': '「{name}」の有料 API の利用可否をテストしますか?', - 'quota.probe.confirmButton': 'テストを実行', - 'quota.probe.running': '利用可否をテスト中…', - 'quota.probe.success': '利用可否のテストに成功しました。残りのクォータは取得されません。', - 'quota.probe.failed': '利用可否のテストに失敗しました:{error}', 'quota.service.xaiPaidAccount': '有料 API アカウント', - 'quota.service.xaiPaidQuotaUnavailable': 'このアカウントの残りクォータは提供されていません。接続の確認は「利用可否をテスト」から実行してください。', - 'quota.service.error.xaiProbeOnly': 'この利用可否テストは xAI 認証情報のみをサポートします', + 'quota.service.xaiPaidQuotaUnavailable': 'このアカウントの残りクォータは提供されていません。', 'quota.confirm.button': 'リセットを実行', 'quota.confirm.applicableLabel': '現在適用可能な回数', 'quota.resetting': 'リセットを送信してクォータを更新中…', @@ -218,11 +210,7 @@ export const jaOverrides = { 'quota.subscriptionExpiry': 'サブスクリプション期限:{time}', 'quota.resetApplicable': '現在適用可能:{count} 回', 'quota.resetCreditsWarning': 'リセット回数の詳細取得に失敗:{error}', - 'quota.xaiProbeConfirm': '最小限の grok-4.5 リクエストを 1 回送信し、少額の料金が発生する可能性があります。利用可否のみをテストし、残りのクォータは取得しません。', 'quota.service.window.sevenDayFable': '7 日間 Fable 枠', - 'quota.service.xaiPaidHealth': '有料 API 利用可能', - 'quota.service.xaiPaidHealthDetail': '短い会話テストに成功。残りクォータは提供されていません', - 'quota.service.error.xaiProbeRequired': '有料 API テストには確認が必要です。課金リクエストは送信していません', 'quota.service.error.resetCreditsInvalid': 'リセット回数 API のデータ形式を認識できません', 'quota.confirm.title': '「{name}」の Codex クォータをリセットしますか?', 'quota.confirm.cost': 'この操作では手動リセットを 1 回消費します。', diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 2dc6268..f37c966 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -173,16 +173,8 @@ export const en: Record = { 'quota.empty.description': 'Add a credential that supports quota queries under Auth Files first.', 'quota.unknownProvider': 'Unknown', 'common.confirm': 'Confirm', - 'quota.probe.button': 'Test Availability', - 'quota.probe.title': 'Test xAI Paid API', - 'quota.probe.confirm': 'Test paid API availability for "{name}"?', - 'quota.probe.confirmButton': 'Confirm Test', - 'quota.probe.running': 'Testing availability…', - 'quota.probe.success': 'Availability test passed; this test does not report remaining quota.', - 'quota.probe.failed': 'Availability test failed: {error}', 'quota.service.xaiPaidAccount': 'Paid API account', - 'quota.service.xaiPaidQuotaUnavailable': 'Remaining quota is not provided for this account. Use Test Availability separately to check the connection.', - 'quota.service.error.xaiProbeOnly': 'This availability test only supports xAI credentials', + 'quota.service.xaiPaidQuotaUnavailable': 'Remaining quota is not provided for this account.', 'quota.confirm.button': 'Confirm Reset', 'quota.confirm.applicableLabel': 'Currently applicable resets', 'quota.resetting': 'Submitting reset and refreshing quota…', @@ -205,11 +197,7 @@ export const en: Record = { 'quota.subscriptionExpiry': 'Subscription expires: {time}', 'quota.resetApplicable': 'Currently applicable: {count}', 'quota.resetCreditsWarning': 'Reset credit details unavailable: {error}', - 'quota.xaiProbeConfirm': 'This sends one minimal grok-4.5 request and may incur a small charge. It only tests availability and does not report remaining quota.', 'quota.service.window.sevenDayFable': '7-day Fable window', - 'quota.service.xaiPaidHealth': 'Paid API available', - 'quota.service.xaiPaidHealthDetail': 'Tiny chat probe succeeded; remaining quota is not provided', - 'quota.service.error.xaiProbeRequired': 'Paid API health probing requires confirmation; no billable request was sent', 'quota.service.error.resetCreditsInvalid': 'The reset credits endpoint returned unrecognized data', 'quota.confirm.title': 'Reset the Codex quota for “{name}”?', 'quota.confirm.cost': 'This will consume one manual reset credit.', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 0019067..0c4f5fe 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -172,16 +172,8 @@ export const zhCN = { 'quota.empty.description': '先在凭证文件中添加支持配额查询的凭据。', 'quota.unknownProvider': '未知', 'common.confirm': '确认', - 'quota.probe.button': '测试可用性', - 'quota.probe.title': '测试 xAI 付费 API', - 'quota.probe.confirm': '确认测试“{name}”的付费 API 可用性吗?', - 'quota.probe.confirmButton': '确认测试', - 'quota.probe.running': '正在测试可用性…', - 'quota.probe.success': '可用性测试通过;此操作不提供剩余额度。', - 'quota.probe.failed': '可用性测试失败:{error}', 'quota.service.xaiPaidAccount': '付费 API 账号', - 'quota.service.xaiPaidQuotaUnavailable': '此账号不提供剩余额度。如需检测连接,请单独点击“测试可用性”。', - 'quota.service.error.xaiProbeOnly': '只有 xAI 凭证支持此可用性测试', + 'quota.service.xaiPaidQuotaUnavailable': '此账号不提供剩余额度。', 'quota.confirm.button': '确认重置', 'quota.confirm.applicableLabel': '当前适用次数', 'quota.resetting': '正在提交重置并刷新额度…', @@ -204,11 +196,7 @@ export const zhCN = { 'quota.subscriptionExpiry': '订阅到期:{time}', 'quota.resetApplicable': '当前适用:{count} 次', 'quota.resetCreditsWarning': '重置次数详情查询失败:{error}', - 'quota.xaiProbeConfirm': '将发送一次极短的 grok-4.5 请求,可能产生少量费用。此操作仅测试可用性,不会返回剩余额度。', 'quota.service.window.sevenDayFable': '7 天 Fable 窗口', - 'quota.service.xaiPaidHealth': '付费 API 可用', - 'quota.service.xaiPaidHealthDetail': '极短对话探测成功;上游未提供剩余额度', - 'quota.service.error.xaiProbeRequired': '付费 API 可用性探测需要确认,尚未发送计费请求', 'quota.service.error.resetCreditsInvalid': '重置次数接口返回了无法识别的数据', 'quota.confirm.title': '确认重置“{name}”的 Codex 额度吗?', 'quota.confirm.cost': '本操作将消耗 1 次主动重置机会。', diff --git a/src/pages/AuthFileManagementPage.tsx b/src/pages/AuthFileManagementPage.tsx index 53a4713..5e97a87 100644 --- a/src/pages/AuthFileManagementPage.tsx +++ b/src/pages/AuthFileManagementPage.tsx @@ -1,7 +1,6 @@ import { ChangeEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useConfirmation } from '../components/ConfirmationDialog'; import { QuotaActionFeedback } from '../components/QuotaActionFeedback'; -import { probeXaiWithConfirmation } from '../services/quotaActions'; import { InlineNotice, useAppNotice } from '../appNotice'; import { AuthFileModelsDialog } from '../components/AuthFileModelsDialog'; import { @@ -121,7 +120,7 @@ function AuthFileQuotaSummary({ quota }: { quota: QuotaState }) { return (
- {t(quota.pendingAction === 'probe' ? 'quota.probe.running' : 'authFiles.quota.loading')} + {t('authFiles.quota.loading')}
); } @@ -235,20 +234,6 @@ export function AuthFileManagementPage() { }); }; - const probeXai = async (file: AuthFile) => { - setError(''); - try { - await probeXaiWithConfirmation(file, () => askConfirmation({ - title: t('quota.probe.title'), - message: t('quota.probe.confirm', { name: fileName(file) }), - warning: t('quota.xaiProbeConfirm'), - confirmText: t('quota.probe.confirmButton'), - })); - } catch (requestError) { - setError(String(requestError)); - } - }; - const closeOauthModels = () => { if (oauthModelSaveRef.current) return; oauthModelRequestRef.current += 1; @@ -558,7 +543,6 @@ export function AuthFileManagementPage() {
{quotaProviderForFile(file) && !disabled ? : null} - {quotaProviderForFile(file) === 'xai' ? : null} {providerKey(file) ? : null} {providerKey(file) ? : null} diff --git a/src/pages/QuotaPage.tsx b/src/pages/QuotaPage.tsx index 8bb5d6b..4978fd6 100644 --- a/src/pages/QuotaPage.tsx +++ b/src/pages/QuotaPage.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { AlertCircle, LoaderCircle, RefreshCw } from 'lucide-react'; import { useConfirmation } from '../components/ConfirmationDialog'; import { QuotaActionFeedback } from '../components/QuotaActionFeedback'; -import { canResetCodexQuota, probeXaiWithConfirmation, resetCodexQuotaWithConfirmation } from '../services/quotaActions'; +import { canResetCodexQuota, resetCodexQuotaWithConfirmation } from '../services/quotaActions'; import antigravityIcon from '../assets/icons/antigravity.svg'; import claudeIcon from '../assets/icons/claude.svg'; import codexIcon from '../assets/icons/codex.svg'; @@ -112,20 +112,6 @@ export function QuotaPage() { } }, [askConfirmation, locale, t]); - const probeXai = useCallback(async (file: AuthFile) => { - setError(''); - try { - await probeXaiWithConfirmation(file, () => askConfirmation({ - title: t('quota.probe.title'), - message: t('quota.probe.confirm', { name: fileName(file) }), - warning: t('quota.xaiProbeConfirm'), - confirmText: t('quota.probe.confirmButton'), - })); - } catch (requestError) { - setError(String(requestError)); - } - }, [askConfirmation, t]); - const refreshAll = useCallback(async () => { if (Object.values(getQuotaCacheSnapshot()).some((quota) => quota.status === 'loading')) return; setRefreshing(true); @@ -192,7 +178,7 @@ export function QuotaPage() { {grouped.map(([provider, items]) => (

{providerMeta[provider].label}

{t(items.length === 1 ? 'quota.credentials.one' : 'quota.credentials.other', { count: items.length })}
-
{items.map(({ file, quota }) => void refreshOne(file)} onReset={provider === 'codex' ? () => void resetCodexQuota(file, quota) : undefined} onProbe={provider === 'xai' ? () => void probeXai(file) : undefined} />)}
+
{items.map(({ file, quota }) => void refreshOne(file)} onReset={provider === 'codex' ? () => void resetCodexQuota(file, quota) : undefined} />)}
))}
@@ -201,7 +187,7 @@ export function QuotaPage() { ); } -export function QuotaCard({ file, quota, onRefresh, onReset, onProbe }: { file: AuthFile; quota: QuotaState; onRefresh: () => void; onReset?: () => void; onProbe?: () => void }) { +export function QuotaCard({ file, quota, onRefresh, onReset }: { file: AuthFile; quota: QuotaState; onRefresh: () => void; onReset?: () => void }) { const { locale, t } = useI18n(); const now = useQuotaClock() + (quota.serverTimeOffsetMs ?? 0); const provider = providerForFile(file); @@ -213,13 +199,12 @@ export function QuotaCard({ file, quota, onRefresh, onReset, onProbe }: { file:
{name}{provider ? providerMeta[provider].label : t('quota.unknownProvider')}{quota.plan ? ' · ' + quota.plan : ''}
{onReset && (quota.resetCredits ?? 0) > 0 ? : null} - {onProbe ? : null}
{quota.status === 'idle' ?
{disabled ? t('quota.fileDisabled') : t('quota.notFetched')}
: null} - {quota.status === 'loading' ?
{t(quota.pendingAction === 'reset' ? 'quota.resetting' : quota.pendingAction === 'probe' ? 'quota.probe.running' : 'quota.querying')}
: null} + {quota.status === 'loading' ?
{t(quota.pendingAction === 'reset' ? 'quota.resetting' : 'quota.querying')}
: null} {quota.status === 'error' ?
{quota.error}
: null} {quota.status === 'success' && provider === 'codex' ?
{t('quota.resetCredits')} {quota.resetCredits ?? '—'} diff --git a/src/services/quotaActions.ts b/src/services/quotaActions.ts index 4419fa0..1d9d9d4 100644 --- a/src/services/quotaActions.ts +++ b/src/services/quotaActions.ts @@ -6,7 +6,7 @@ import { } from './quotaCache'; import { readBoolean } from './managementApi'; import { - consumeCodexResetCredit, idleQuota, probeXaiAvailability, providerForFile, quotaKey, + consumeCodexResetCredit, idleQuota, providerForFile, quotaKey, type AuthFile, type QuotaState, } from './quotaService'; @@ -23,7 +23,7 @@ export const canResetCodexQuota = (file: AuthFile, quota: QuotaState): boolean = async function runConfirmedQuotaAction( file: AuthFile, - action: 'reset' | 'probe', + action: 'reset', confirmAction: () => Promise, execute: (file: AuthFile) => Promise, ): Promise { @@ -46,7 +46,7 @@ async function runConfirmedQuotaAction( updateQuotaCache((current) => ({ ...current, [key]: pending! })); const result = await execute(file); if (result.status === 'error') { - const status = action === 'reset' ? 'refresh-error' : 'error'; + const status = 'refresh-error'; commit({ ...previous, actionResult: { action, status, error: result.error } }); return status; } @@ -65,8 +65,3 @@ export function resetCodexQuotaWithConfirmation(file: AuthFile, confirmReset: () if (!canResetCodexQuota(file, getQuotaCacheSnapshot()[quotaKey(file)] ?? idleQuota())) return Promise.resolve('cancelled'); return runConfirmedQuotaAction(file, 'reset', confirmReset, consumeCodexResetCredit); } - -export function probeXaiWithConfirmation(file: AuthFile, confirmProbe: () => Promise): Promise { - if (providerForFile(file) !== 'xai') return Promise.resolve('cancelled'); - return runConfirmedQuotaAction(file, 'probe', confirmProbe, probeXaiAvailability); -} diff --git a/src/services/quotaService.ts b/src/services/quotaService.ts index 3fee422..4fbf68a 100644 --- a/src/services/quotaService.ts +++ b/src/services/quotaService.ts @@ -37,8 +37,8 @@ export type QuotaState = { subscriptionActiveUntil?: string; serverTimeOffsetMs?: number; fetchedAt?: number; - pendingAction?: 'reset' | 'probe'; - actionResult?: { action: 'reset' | 'probe'; status: 'success' | 'refresh-error' | 'error'; error?: string }; + pendingAction?: 'reset'; + actionResult?: { action: 'reset'; status: 'success' | 'refresh-error' | 'error'; error?: string }; }; export const idleQuota = (): QuotaState => ({ status: 'idle', rows: [] }); @@ -471,11 +471,6 @@ export const quotaRowsFor = (provider: QuotaProvider, payload: unknown): QuotaRo remainingPercent: null, detail: quotaText('quota.service.xaiPaidQuotaUnavailable'), }]; - if (value.mode === 'paid-health') return [{ - label: quotaText('quota.service.xaiPaidHealth'), - remainingPercent: null, - detail: quotaText('quota.service.xaiPaidHealthDetail'), - }]; const payloads = isRecord(value.weekly) || isRecord(value.monthly) ? [value.weekly, value.monthly] : [value]; @@ -661,20 +656,6 @@ const requestQuotaPayload = async ( return parseBody(response.body ?? response.bodyText); }; -const callXaiPaidHealth = async (authIndex: string): Promise => { - const header = { Authorization: 'Bearer $TOKEN$', accept: 'application/json' }; - const [profile, chat] = await Promise.allSettled([ - requestQuotaPayload(authIndex, 'https://api.x.ai/v1/me', header, 'GET', undefined, 15_000), - requestQuotaPayload(authIndex, 'https://api.x.ai/v1/chat/completions', { - ...header, 'Content-Type': 'application/json', - }, 'POST', JSON.stringify({ - model: 'grok-4.5', messages: [{ role: 'user', content: 'ping' }], max_tokens: 1, stream: false, - }), 15_000), - ]); - if (chat.status === 'rejected') throw chat.reason; - return { mode: 'paid-health', plan_type: 'Paid', profile: profile.status === 'fulfilled' ? profile.value : null }; -}; - const callXaiQuota = async (file: AuthFile): Promise => { const authIndex = normalizeAuthIndex(file.auth_index ?? file.authIndex); if (!authIndex) throw new Error(quotaText('quota.service.error.missingAuthIndex')); @@ -984,14 +965,3 @@ function runQuotaMutation(file: AuthFile, mutate: () => Promise): Pr export function consumeCodexResetCredit(file: AuthFile): Promise { return runQuotaMutation(file, () => consumeCodexResetCreditSnapshot(file)); } - -export function probeXaiAvailability(file: AuthFile): Promise { - return runQuotaMutation(file, async () => { - if (providerForFile(file) !== 'xai') throw new Error(quotaText('quota.service.error.xaiProbeOnly')); - if (booleanValue(file.disabled) === true) throw new Error(quotaText('quota.fileDisabled')); - const authIndex = normalizeAuthIndex(file.auth_index ?? file.authIndex); - if (!authIndex) throw new Error(quotaText('quota.service.error.missingAuthIndex')); - const payload = await callXaiPaidHealth(authIndex); - return { status: 'success', rows: quotaRowsFor('xai', payload), plan: 'Paid', fetchedAt: Date.now() }; - }); -} diff --git a/tests/quotaConfirmation.test.ts b/tests/quotaConfirmation.test.ts index 15f17ca..d1e61d2 100644 --- a/tests/quotaConfirmation.test.ts +++ b/tests/quotaConfirmation.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { clearMocks, mockIPC } from '@tauri-apps/api/mocks'; -import { canResetCodexQuota, probeXaiWithConfirmation, resetCodexQuotaWithConfirmation } from '../src/services/quotaActions'; +import { canResetCodexQuota, resetCodexQuotaWithConfirmation } from '../src/services/quotaActions'; import { getQuotaCacheSnapshot, pruneQuotaCache, updateQuotaCache } from '../src/services/quotaCache'; import { quotaKey, type QuotaState } from '../src/services/quotaService'; @@ -139,15 +139,6 @@ describe('quota action confirmation with fully mocked IPC', () => { expect(upstreamCalls.filter((request) => request.url.endsWith('/consume'))).toHaveLength(1); }); - it('only runs a paid availability test after separate explicit confirmation', async () => { - const xai = { name: 'xai-test.json', provider: 'xai', auth_index: 'test-xai' }; - await probeXaiWithConfirmation(xai, async () => false); - expect(upstreamCalls).toHaveLength(0); - expect(await probeXaiWithConfirmation(xai, async () => true)).toBe('success'); - expect(upstreamCalls.filter((request) => request.url.endsWith('/chat/completions'))).toHaveLength(1); - expect(upstreamCalls.some((request) => request.url.endsWith('/consume'))).toBe(false); - }); - it('keeps application confirmations out of native and browser dialog APIs', async () => { for (const name of ['QuotaPage', 'AuthFileManagementPage', 'ApiAccessPage', 'ThinkingAliasesPage', 'UsageRecordsPage']) { const source = await Bun.file(new URL('../src/pages/' + name + '.tsx', import.meta.url)).text(); diff --git a/tests/quotaRendering.test.tsx b/tests/quotaRendering.test.tsx index 2562131..649837e 100644 --- a/tests/quotaRendering.test.tsx +++ b/tests/quotaRendering.test.tsx @@ -20,10 +20,12 @@ describe('quota card rendering', () => { expect(html).toContain('订阅到期'); }); - it('付费 API 健康状态不画成 0% 或 100% 的额度条', () => { - const html = render({ status: 'success', rows: [{ label: '付费 API 可用', remainingPercent: null, detail: '上游未提供剩余额度' }] }, 'xai'); + it('xAI 付费账号保留额度说明和刷新入口,不显示可用性测试', () => { + const html = render({ status: 'success', rows: [{ label: '付费 API 账号', remainingPercent: null, detail: '上游未提供剩余额度' }] }, 'xai'); expect(html).toContain('上游未提供剩余额度'); expect(html).not.toContain('real-quota-track'); + expect(html).not.toContain('测试可用性'); + expect(html).toContain('获取/刷新额度'); }); it('缓存中的原始重置时间提供动态提示,过期额度不伪造为已恢复', () => { diff --git a/tests/quotaRequests.test.ts b/tests/quotaRequests.test.ts index 4df90b4..d90414e 100644 --- a/tests/quotaRequests.test.ts +++ b/tests/quotaRequests.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, spyOn } from 'bun:test'; import { managementApi } from '../src/services/managementApi'; -import { consumeCodexResetCredit, loadQuota, probeXaiAvailability } from '../src/services/quotaService'; +import { consumeCodexResetCredit, loadQuota } from '../src/services/quotaService'; const success = (body: unknown) => ({ status_code: 200, body }); const codexUsage = { @@ -122,7 +122,7 @@ describe('quota API compatibility', () => { }); }); -describe('xAI quota queries and explicit availability tests', () => { +describe('xAI quota queries without paid probes', () => { const file = { name: 'xai.json', provider: 'x-ai', auth_index: 'x' }; it('单个账单接口失败仍展示另一接口的数据,不触发收费探测', async () => { @@ -140,22 +140,10 @@ describe('xAI quota queries and explicit availability tests', () => { const result = await loadQuota({ ...file, using_api: true, prefix: 'paid' }); expect(result.status).toBe('success'); expect(result.rows[0].remainingPercent).toBeNull(); - expect(result.rows[0].detail).toContain('不提供剩余额度'); + expect(result.rows[0].detail).toBe('此账号不提供剩余额度。'); expect(post).not.toHaveBeenCalled(); }); - it('确认后执行极短对话探测,profile 失败不影响结果,也不伪造剩余额度', async () => { - handler = (request) => request.url.endsWith('/me') ? { status_code: 403 } : success({ choices: [] }); - const result = await probeXaiAvailability({ ...file, using_api: true, prefix: 'paid' }); - expect(result).toMatchObject({ status: 'success', plan: 'Paid', rows: [{ remainingPercent: null }] }); - expect(calls).toHaveLength(2); - expect(calls.every((request) => request.url.startsWith('https://api.x.ai/'))).toBe(true); - expect(JSON.parse(calls.find((request) => request.method === 'POST')!.data!)).toEqual({ - model: 'grok-4.5', messages: [{ role: 'user', content: 'ping' }], max_tokens: 1, stream: false, - }); - post.mock.calls.forEach((call: unknown[]) => expect(call[2]).toEqual({ timeoutMs: 15000 })); - }); - it('两个账单均无数据时返回查询错误,不自动发起付费测试', async () => { handler = (request) => request.url.includes('cli-chat-proxy') ? { status_code: 403, body: 'billing denied' } : { status_code: 429, body: 'paid denied' }; @@ -164,12 +152,6 @@ describe('xAI quota queries and explicit availability tests', () => { expect(calls).toHaveLength(2); expect(calls.every((request) => request.method === 'GET')).toBe(true); }); - - it('不允许仅凭 profile 成功把对话失败的付费账户标记为可用', async () => { - handler = (request) => request.url.endsWith('/me') ? success({ user_id: 'u' }) : { status_code: 429, body: 'chat denied' }; - await expect(probeXaiAvailability({ ...file, using_api: true, prefix: 'paid' })) - .rejects.toThrow('chat denied'); - }); }); describe('quota request synchronization', () => { diff --git a/tests/quotaService.test.ts b/tests/quotaService.test.ts index 524dd10..19a65f4 100644 --- a/tests/quotaService.test.ts +++ b/tests/quotaService.test.ts @@ -262,11 +262,11 @@ describe('quotaRowsFor', () => { ]); }); - it('xAI 仅返回产品用量时仍能解析,付费探测不伪造百分比', () => { + it('xAI 仅返回产品用量时仍能解析,付费账号不伪造剩余额度', () => { expect(quotaRowsFor('xai', { config: { productUsage: [{ product: 'grok', usagePercent: 20 }] } })[1]) .toMatchObject({ label: 'grok', remainingPercent: 80 }); - expect(quotaRowsFor('xai', { mode: 'paid-health' })[0]) - .toMatchObject({ label: '付费 API 可用', remainingPercent: null }); + expect(quotaRowsFor('xai', { mode: 'paid-info' })[0]) + .toMatchObject({ label: '付费 API 账号', remainingPercent: null }); }); it('xAI 不从月账单借用周窗口的重置时间', () => {