test(留言分頁): 改用 timeline 分頁讀取留言

Gitea 議題留言端點無法可靠處理分頁;改由 timeline 逐頁篩選 comment 事件並去重,讓抽取、整併與 PR 留言流程取得完整集合。
This commit is contained in:
2026-09-22 14:37:38 +08:00
parent a944141109
commit 437896348a
5 changed files with 66 additions and 42 deletions
+28 -11
View File
@@ -75,9 +75,9 @@ function routes(overrides = {}, { body = FULL_BODY, comments = [] } = {}) {
labels: [{ id: 55, name: 'ready-for-agent' }],
},
},
[`GET /api/v1/repos/${REPO}/issues/${INDEX}/comments`]: {
[`GET /api/v1/repos/${REPO}/issues/${INDEX}/timeline`]: {
status: 200,
body: comments.map((c, i) => ({ id: 100 + i, body: c.body })),
body: comments.map((c, i) => ({ id: 100 + i, type: 'comment', body: c.body })),
},
...overrides,
});
@@ -340,7 +340,7 @@ test('--dry-run 印出將發出的請求,且不碰 Gitea', async (t) => {
json.data.requests.map((r) => `${r.method} ${r.path}`),
[
`GET /repos/${REPO}/issues/${INDEX}`,
`GET /repos/${REPO}/issues/${INDEX}/comments`,
`GET /repos/${REPO}/issues/${INDEX}/timeline`,
],
);
assert.match(
@@ -422,17 +422,20 @@ test('巢狀清單一律攤平,不無聲吃掉內容', async (t) => {
assert.deepEqual(json.data.驗收標準, ['上層項目', '巢狀項目']);
});
test('留言逐頁讀完,不是只讀第一頁', async (t) => {
// 第一頁滿 50 筆就得再翻一頁;第二頁不滿才收手
const page1 = Array.from({ length: 50 }, (_, i) => ({ id: 200 + i }));
const page2 = Array.from({ length: 20 }, (_, i) => ({ id: 300 + i }));
test('留言 timeline 逐頁讀完並去除重複事件', async (t) => {
// 第一頁滿 50 筆就得再翻一頁;第二頁包含重複事件,仍只算一次
const page1 = Array.from({ length: 50 }, (_, i) => ({ id: 200 + i, type: 'comment' }));
const page2 = [
page1.at(-1),
...Array.from({ length: 20 }, (_, i) => ({ id: 300 + i, type: 'comment' })),
];
const reactions = {};
for (const { id } of [...page1, ...page2]) {
reactions[`GET /api/v1/repos/${REPO}/issues/comments/${id}/reactions`] = { status: 200, body: [] };
}
const stub = await withStub(t, {
[`GET /api/v1/repos/${REPO}/issues/${INDEX}/comments`]: (req) => ({
[`GET /api/v1/repos/${REPO}/issues/${INDEX}/timeline`]: (req) => ({
status: 200,
body: req.query.page === '1' ? page1 : page2,
}),
@@ -441,7 +444,21 @@ test('留言逐頁讀完,不是只讀第一頁', async (t) => {
const { json } = await run([], stub);
const commentPages = stub.requests.filter((r) => r.path.endsWith(`/issues/${INDEX}/comments`));
assert.deepEqual(commentPages.map((r) => r.query.page), ['1', '2']);
assert.equal(json.data.未處理留言數, 70, '第二頁的留言也要算進來');
const timelinePages = stub.requests.filter((r) => r.path.endsWith(`/issues/${INDEX}/timeline`));
assert.deepEqual(timelinePages.map((r) => r.query.page), ['1', '2']);
assert.equal(json.data.未處理留言數, 70, '重複事件不應重複計入');
});
test('timeline 讀取失敗時回傳可區分的錯誤', async (t) => {
const stub = await withStub(t, {
[`GET /api/v1/repos/${REPO}/issues/${INDEX}/timeline`]: {
status: 502,
body: { message: 'upstream unavailable' },
},
});
const { json } = await run([], stub);
assert.equal(json.error.code, 'HTTP_ERROR');
assert.match(json.error.message, /502/);
});