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'); +});