From 47529d33c2c9915eb0ab2305cc40a05f3e6f1af0 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 17 Sep 2026 06:22:29 +0000 Subject: [PATCH] =?UTF-8?q?test(issue-update):=20=E8=A6=86=E8=93=8B?= =?UTF-8?q?=E7=B8=BD=E8=A6=BD=E7=B6=B2=E5=9D=80=E7=9A=84=E5=AF=AB=E5=9B=9E?= =?UTF-8?q?=E8=88=87=E5=B0=B1=E5=9C=B0=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) --- test/issue-update.test.js | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/test/issue-update.test.js b/test/issue-update.test.js index bd4819d..9de80bd 100644 --- a/test/issue-update.test.js +++ b/test/issue-update.test.js @@ -249,3 +249,81 @@ test('估算插在段落內容結尾,不會掉到下一個段落裡', async (t '估算要留在關聯段落內', ); }); + +// ── 總覽網頁的連結 ───────────────────────────────────────────────── + +test('把總覽網頁的連結寫進總覽段落', async (t) => { + const stub = await withStub(t, {}, { + body: '## 總覽\n\n一句話總覽。\n\n## 關聯\n\n需求議題:#1\n', + }); + + await run(['--overview-url', 'https://example.com/artifact/abc'], stub); + + const updated = patchOf(stub).body.body; + const overview = updated.slice(0, updated.indexOf('## 關聯')); + assert.match(overview, /圖解版總覽:https:\/\/example\.com\/artifact\/abc/); +}); + +test('連結旁註明 artifact 預設私有', async (t) => { + const stub = await withStub(t, {}, { body: '## 總覽\n\n一句話總覽。\n' }); + + await run(['--overview-url', 'https://example.com/a'], stub); + + assert.match(patchOf(stub).body.body, /私有/); + assert.match(patchOf(stub).body.body, /組織外/); +}); + +test('議題原本的 markdown 白話總覽保留不動', async (t) => { + const stub = await withStub(t, {}, { + body: '## 總覽\n\n這段白話總覽不該被網頁取代。\n\n## 背景\n\n背景說明。\n', + }); + + await run(['--overview-url', 'https://example.com/a'], stub); + + const updated = patchOf(stub).body.body; + assert.match(updated, /這段白話總覽不該被網頁取代。/); + assert.match(updated, /## 背景\n\n背景說明。/); +}); + +test('重跑時原地更新同一行,不會長出第二個連結', async (t) => { + const stub = await withStub(t, {}, { + body: '## 總覽\n\n一句話。\n圖解版總覽:https://example.com/old(此連結預設為私有,組織外無法開啟)\n', + }); + + await run(['--overview-url', 'https://example.com/new'], stub); + + const updated = patchOf(stub).body.body; + assert.equal((updated.match(/圖解版總覽:/g) ?? []).length, 1); + assert.match(updated, /example\.com\/new/); + assert.equal(updated.includes('example.com/old'), false); +}); + +test('連結沒變時不重寫 body', async (t) => { + const stub = await withStub(t, {}, { + body: '## 總覽\n\n一句話。\n圖解版總覽:https://example.com/a(此連結預設為私有,組織外無法開啟)\n', + }); + + await run(['--overview-url', 'https://example.com/a'], stub); + + assert.equal('body' in patchOf(stub).body, false); +}); + +test('不是網址時擋在打 Gitea 之前', async (t) => { + const stub = await withStub(t); + + const { json } = await run(['--overview-url', '不是網址'], stub); + + assert.equal(json.error.code, 'BAD_OVERVIEW_URL'); + assert.equal(stub.requests.length, 0); +}); + +test('總覽網頁與其他欄位可以一次送出', async (t) => { + const stub = await withStub(t); + + await run(['--overview-url', 'https://example.com/a', '--due-date', '2026-09-24'], stub); + + const patches = stub.requests.filter((r) => r.method === 'PATCH' && !r.path.endsWith('/0')); + assert.equal(patches.length, 1); + assert.match(patches[0].body.body, /圖解版總覽/); + assert.equal(patches[0].body.due_date, '2026-09-24T00:00:00Z'); +});