From 1f9e0d906c298cc324f0aa4ff93ebaf1b81f2724 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 23 Jun 2026 13:34:41 +0800 Subject: [PATCH] =?UTF-8?q?test(ai-review):=20=E8=A3=9C=E9=9D=9E=E6=95=B4?= =?UTF-8?q?=E6=95=B8=20idx=E3=80=81=E7=A9=BA=20apiKeys=20=E8=88=87=20limit?= =?UTF-8?q?=20=E7=82=BA=200=20=E7=9A=84=E9=82=8A=E7=95=8C=E6=B8=AC?= =?UTF-8?q?=E8=A9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/resolve.test.js | 11 +++++++++++ app/usage.test.js | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/app/resolve.test.js b/app/resolve.test.js index 1c00f10..2fd755d 100644 --- a/app/resolve.test.js +++ b/app/resolve.test.js @@ -122,6 +122,17 @@ describe('judgeConversationsResolved', () => { ]); }); + it('ignores entries whose idx is not an integer (e.g. a string)', async () => { + const items = [{ idx: 0 }, { idx: 1 }]; + // 字串 idx '0' 不可冒充整數 idx 0 把它改成 resolved + const chatFn = async () => [{ idx: '0', resolved: true }, { idx: 1.5, resolved: true }, { idx: 1, resolved: true }]; + const verdicts = await judgeConversationsResolved(items, chatFn); + assert.deepEqual(verdicts, [ + { idx: 0, resolved: false }, + { idx: 1, resolved: true }, + ]); + }); + it('propagates errors thrown by chatFn to the caller', async () => { await assert.rejects( () => judgeConversationsResolved([{ idx: 0 }], async () => { throw new Error('LLM down'); }), diff --git a/app/usage.test.js b/app/usage.test.js index 7a1fd5d..20afd4e 100644 --- a/app/usage.test.js +++ b/app/usage.test.js @@ -123,6 +123,14 @@ describe('fetchAccountQuota', () => { assert.equal(q.available, false); assert.match(q.reason, /未支援/); }); + + it('degrades gracefully when apiKeys is empty or undefined', async () => { + const get = async () => { throw new Error('should not be called'); }; + // 空陣列 / 未提供 key 都不應丟錯,依平台回報無法取得或不適用 + assert.equal((await fetchAccountQuota('openai', { apiKeys: [], baseURL: 'https://api.openai.com/v1' }, { get })).available, false); + assert.equal((await fetchAccountQuota('ollama', { apiKeys: [] }, { get })).available, false); + assert.equal((await fetchAccountQuota('claude', {}, { get })).available, false); + }); }); describe('recordRateLimit / getRateLimit', () => { @@ -178,6 +186,12 @@ describe('resolveRemainingPercent', () => { assert.equal(pct.percent, null); assert.match(pct.reason, /無上限/); }); + + it('does not divide by zero when quota.limit is 0', () => { + const pct = resolveRemainingPercent({ available: true, used: 5, limit: 0, currency: 'USD' }, { hasData: false }); + assert.equal(pct.percent, null); // limit > 0 守衛擋掉除以零 + assert.ok(typeof pct.reason === 'string' && pct.reason.length > 0); + }); }); describe('formatUsageStats', () => {