test(ai-review): 補關閉所有 comment、部分 resolve 失敗、百分比邊界與 usageSection 排版測試
This commit is contained in:
@@ -303,6 +303,8 @@ describe('postFindingsReview', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert.doesNotMatch(reviewCalls[0].body, /AI 助理使用量/);
|
assert.doesNotMatch(reviewCalls[0].body, /AI 助理使用量/);
|
||||||
|
// usageSection 省略時,body 不應殘留多餘的尾端空白/換行
|
||||||
|
assert.equal(reviewCalls[0].body, reviewCalls[0].body.trimEnd());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('separates old and new findings in default review statistics', async () => {
|
it('separates old and new findings in default review statistics', async () => {
|
||||||
|
|||||||
@@ -170,6 +170,39 @@ describe('reconcileConversations', () => {
|
|||||||
assert.deepEqual(result.carriedFindings, []);
|
assert.deepEqual(result.carriedFindings, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('resolves every unresolved comment id, not just the first per path/line group', async () => {
|
||||||
|
const closedIds = [];
|
||||||
|
const deps = baseDeps();
|
||||||
|
deps.listComments = async () => [
|
||||||
|
{ id: 10, path: 'a.js', position: 5, body: reviewBody('🔴 嚴重', 'Assassin', 'p', 's10') },
|
||||||
|
{ id: 11, path: 'a.js', position: 5, body: reviewBody('🔴 嚴重', 'Mage', 'p', 's11') }, // 同 path|line → 同一組
|
||||||
|
{ id: 12, path: '', position: 0, body: 'no path' }, // 無 path → 不分組但仍要關
|
||||||
|
{ id: 13, path: 'b.js', position: 8, body: 'done', resolver: { login: 'dev' } }, // 已 resolve → 不關
|
||||||
|
];
|
||||||
|
deps.resolveComment = async (id) => { closedIds.push(id); return { ok: true }; };
|
||||||
|
deps.judge = async (items) => items.map(it => ({ idx: it.idx, verdict: 'open' }));
|
||||||
|
|
||||||
|
const result = await reconcileConversations(deps);
|
||||||
|
|
||||||
|
// 同組的 10、11 都關,無 path 的 12 也關;已 resolve 的 13 不關
|
||||||
|
assert.deepEqual(closedIds.sort((a, b) => a - b), [10, 11, 12]);
|
||||||
|
assert.equal(result.closedCount, 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('counts only successful closes when some resolve calls fail', async () => {
|
||||||
|
const deps = baseDeps();
|
||||||
|
// a.js(id1) 關閉成功、b.js(id2) 關閉失敗(c.js 已 resolved 略過)
|
||||||
|
deps.resolveComment = async (id) => { if (id === 2) throw new Error('403'); return { ok: true }; };
|
||||||
|
deps.judge = async (items) => items.map(it => ({ idx: it.idx, verdict: 'resolved' }));
|
||||||
|
|
||||||
|
const result = await reconcileConversations(deps);
|
||||||
|
|
||||||
|
assert.equal(result.closedCount, 1); // 僅 id1 成功關閉
|
||||||
|
// findings 分流不受 resolve 成敗影響:兩個都判 resolved
|
||||||
|
assert.equal(result.resolvedCount, 2);
|
||||||
|
assert.deepEqual(result.resolvedFindings.map(f => f.location).sort(), ['a.js:10', 'b.js:20']);
|
||||||
|
});
|
||||||
|
|
||||||
it('carries open-verdict conversations into findings while still closing them', async () => {
|
it('carries open-verdict conversations into findings while still closing them', async () => {
|
||||||
const closedIds = [];
|
const closedIds = [];
|
||||||
const deps = baseDeps();
|
const deps = baseDeps();
|
||||||
|
|||||||
@@ -192,6 +192,13 @@ describe('resolveRemainingPercent', () => {
|
|||||||
assert.equal(pct.percent, null); // limit > 0 守衛擋掉除以零
|
assert.equal(pct.percent, null); // limit > 0 守衛擋掉除以零
|
||||||
assert.ok(typeof pct.reason === 'string' && pct.reason.length > 0);
|
assert.ok(typeof pct.reason === 'string' && pct.reason.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('reports 100% when remaining equals limit and 0% when remaining is 0', () => {
|
||||||
|
const full = resolveRemainingPercent({ available: true, used: 0, limit: 100, remaining: 100, currency: 'USD' }, null);
|
||||||
|
assert.equal(full.percent, 100);
|
||||||
|
const empty = resolveRemainingPercent({ available: true, used: 100, limit: 100, remaining: 0, currency: 'USD' }, null);
|
||||||
|
assert.equal(empty.percent, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('formatUsageStats', () => {
|
describe('formatUsageStats', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user