feat(ai-review 統計): 將統計改為新舊問題分列
This commit is contained in:
+45
-5
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { saveFindings, parseLocation, postNewCriticalComments, postFindingsReview } from './comments.js';
|
||||
import { saveFindings, parseLocation, postNewCriticalComments, postFindingsReview, formatFindingsStats } from './comments.js';
|
||||
import { FINDINGS_PATH } from './config.js';
|
||||
|
||||
describe('saveFindings', () => {
|
||||
@@ -96,6 +96,24 @@ describe('parseLocation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatFindingsStats', () => {
|
||||
it('formats old and new findings by severity', () => {
|
||||
const stats = formatFindingsStats([
|
||||
{ level: 'critical', is_new: false },
|
||||
{ level: 'warning', is_new: true },
|
||||
{ level: 'info' },
|
||||
{ level: 'custom', is_new: true },
|
||||
]);
|
||||
|
||||
assert.equal(stats, [
|
||||
'| 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 |',
|
||||
'| --- | --- | --- | --- |',
|
||||
'| 舊問題 | 1 筆 | 0 筆 | 0 筆 |',
|
||||
'| 新問題 | 0 筆 | 1 筆 | 1 筆 |',
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('postNewCriticalComments', () => {
|
||||
const critical = { level: 'critical', role: 'Rex', location: 'app/preflight.js:19', suggestion: '修這個', is_new: true };
|
||||
|
||||
@@ -190,6 +208,11 @@ describe('postFindingsReview', () => {
|
||||
const REVIEW_SEVERITY_LABELS = ['🔴 嚴重', '🟡 警告', '🔵 建議'];
|
||||
const REVIEW_SEVERITY_PATTERN = new RegExp(`\\*\\*嚴重等級\\*\\*:(${REVIEW_SEVERITY_LABELS.join('|')})(?:\\n|$)`);
|
||||
|
||||
/**
|
||||
* 從 review comment body 擷取嚴重等級標籤。
|
||||
* @param {object | null | undefined} comment - 預期包含 body 欄位的 review comment。
|
||||
* @returns {string | undefined} 嚴重等級標籤;格式不符時回傳 undefined。
|
||||
*/
|
||||
function reviewSeverityLabel(comment) {
|
||||
return comment?.body?.match(REVIEW_SEVERITY_PATTERN)?.[1];
|
||||
}
|
||||
@@ -221,14 +244,15 @@ describe('postFindingsReview', () => {
|
||||
];
|
||||
|
||||
await postFindingsReview(findings, {
|
||||
summaryFindings: findings.filter(f => f.is_new !== false),
|
||||
summaryFindings: findings,
|
||||
commentFindings: findings,
|
||||
postReview: async (args) => { reviewCalls.push(args); },
|
||||
});
|
||||
|
||||
assert.equal(reviewCalls.length, 1);
|
||||
assert.match(reviewCalls[0].body, /\| 🔴 嚴重 \| 🟡 警告 \| 🔵 建議 \|/);
|
||||
assert.match(reviewCalls[0].body, /\| 0 筆 \| 1 筆 \| 1 筆 \|/);
|
||||
assert.match(reviewCalls[0].body, /\| 類型 \| 🔴 嚴重 \| 🟡 警告 \| 🔵 建議 \|/);
|
||||
assert.match(reviewCalls[0].body, /\| 舊問題 \| 1 筆 \| 0 筆 \| 0 筆 \|/);
|
||||
assert.match(reviewCalls[0].body, /\| 新問題 \| 0 筆 \| 1 筆 \| 1 筆 \|/);
|
||||
assert.deepEqual(
|
||||
reviewCalls[0].comments.map(c => c.path),
|
||||
['app/a.js', 'app/b.js', 'app/c.js'],
|
||||
@@ -248,6 +272,22 @@ describe('postFindingsReview', () => {
|
||||
assert.match(reviewCalls[0].comments[0].body, /建議.*C/s);
|
||||
});
|
||||
|
||||
it('separates old and new findings in default review statistics', async () => {
|
||||
const reviewCalls = [];
|
||||
await postFindingsReview([
|
||||
{ level: 'critical', role: 'Rex', location: 'app/a.js:10', suggestion: 'old critical', is_new: false },
|
||||
{ level: 'warning', role: 'Leo', location: 'app/b.js:20', suggestion: 'new warning', is_new: true },
|
||||
{ level: 'info', role: 'Maya', location: 'app/c.js:30', suggestion: 'new info' },
|
||||
], {
|
||||
postReview: async (args) => { reviewCalls.push(args); },
|
||||
});
|
||||
|
||||
assert.equal(reviewCalls.length, 1);
|
||||
assert.match(reviewCalls[0].body, /\| 舊問題 \| 1 筆 \| 0 筆 \| 0 筆 \|/);
|
||||
assert.match(reviewCalls[0].body, /\| 新問題 \| 0 筆 \| 1 筆 \| 1 筆 \|/);
|
||||
assert.equal(reviewCalls[0].comments.length, 3);
|
||||
});
|
||||
|
||||
it('only adds comments for findings with parseable file and line', async () => {
|
||||
const reviewCalls = [];
|
||||
await postFindingsReview([
|
||||
@@ -258,7 +298,7 @@ describe('postFindingsReview', () => {
|
||||
});
|
||||
|
||||
assert.equal(reviewCalls.length, 1);
|
||||
assert.match(reviewCalls[0].body, /\| 1 筆 \| 1 筆 \| 0 筆 \|/);
|
||||
assert.match(reviewCalls[0].body, /\| 新問題 \| 1 筆 \| 1 筆 \| 0 筆 \|/);
|
||||
assert.equal(reviewCalls[0].comments.length, 1);
|
||||
assert.equal(reviewCalls[0].comments[0].path, 'app/b.js');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user