From a1bbd78cb4c5cf877d3feaa6a1ece9777e944963 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 17 Sep 2026 08:46:35 +0000 Subject: [PATCH] =?UTF-8?q?test(sdlc-fix-assets):=20=E6=96=B0=E5=A2=9E=20s?= =?UTF-8?q?dlc-fix=20=E6=B5=81=E7=A8=8B=E6=AD=A3=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 分類必改/建議、不確定時停下來問、最後那則摘要——這三件腳本擋不住,只有正本做得到。 標不了的那幾則要在摘要裡單獨點出來,否則 reviewer 掃 reaction 與 resolve 時會以為它們 被跳過了。留言指向的程式碼已被改掉時不要硬試,列進「無法處理」讓使用者自己回。 --- test/sdlc-fix-assets.test.js | 133 +++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 test/sdlc-fix-assets.test.js diff --git a/test/sdlc-fix-assets.test.js b/test/sdlc-fix-assets.test.js new file mode 100644 index 0000000..a23866a --- /dev/null +++ b/test/sdlc-fix-assets.test.js @@ -0,0 +1,133 @@ +/** + * /sdlc-fix 的流程正本。 + * + * 這一段有三件事只有正本做得到,腳本擋不住:分類必改/建議、不確定時停下來問、 + * 以及最後那則摘要。寫漏任何一件,reviewer 的意見就會被靜靜跳過——而那正是這個指令 + * 存在的理由。 + */ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { assertNeutralPrompt, readPrompt } from './helpers/prompt-doc.js'; + +const prompt = readPrompt('sdlc-fix'); +const steps = prompt.slice(prompt.indexOf('## 1.'), prompt.indexOf('## 邊界')); + +test('正本平台中立,description 前綴正確', () => { + assertNeutralPrompt(prompt, 'sdlc-fix'); +}); + +test('指名兩支腳本,順序為先讀再回', () => { + const order = ['pr-comments.js', 'pr-reply.js']; + const positions = order.map((name) => steps.indexOf(name)); + assert.equal(positions.every((p) => p >= 0), true, '兩支腳本都要被指名'); + assert.deepEqual([...positions].sort((a, b) => a - b), positions); +}); + +test('三類留言都點名,且交代行內的 diff 要看', () => { + for (const kind of ['一般留言', 'review 總評', '行內留言']) { + assert.match(steps, new RegExp(kind), `缺少:${kind}`); + } + assert.match(steps, /不要略過不看/); +}); + +test('三類的標記機制都交代了,並說明 +1 要是自己打的', () => { + assert.match(steps, /三類都標記得了/); + assert.match(steps, /resolve/); + assert.match(steps, /自己打的/); + assert.match(steps, /我同意/, '要說出為什麼別人的 \+1 不算'); +}); + +test('標不了的那幾則要在摘要裡單獨點出來', () => { + assert.match(steps, /可標記/); + assert.match(steps, /單獨點出來|單獨\n? 列出來|單獨列出來/); +}); + +test('留言指向的程式碼已被改掉時的處置有交代', () => { + assert.match(steps, /位置對不上/); + assert.match(steps, /不要硬試/); +}); + +// ── 分類 ─────────────────────────────────────────────────────────── + +test('必改與建議各有判斷依據,不是只給兩個詞', () => { + assert.match(steps, /\*\*必改\*\* — .{10,}/); + assert.match(steps, /\*\*建議\*\* — .{10,}/); +}); + +test('分類結果要先呈現給使用者再動手', () => { + assert.match(steps, /先呈現給使用者/); +}); + +test('拿不準時往必改那邊靠,並說明為什麼', () => { + assert.match(steps, /歸到必改/); + assert.match(steps, /代價不對稱/); +}); + +// ── 不確定就問 ───────────────────────────────────────────────────── + +test('一次問一題,選項含手動輸入', () => { + assert.match(steps, /一次問一題/); + assert.match(steps, /手動輸入/); +}); + +test('該問的情況有列舉,不是一句「不確定就問」', () => { + const section = steps.slice(steps.indexOf('## 3.'), steps.indexOf('## 4.')); + const bullets = section.match(/^- /gm) ?? []; + assert.ok(bullets.length >= 3, `該問的情況要列得出來,只找到 ${bullets.length} 條`); + assert.match(section, /推了新 commit/, '位置對不上是最常見的一種,要點名'); +}); + +test('說明了硬改的代價', () => { + assert.match(steps, /比多問一題貴得多/); +}); + +// ── 逐則處理 ─────────────────────────────────────────────────────── + +test('要一則一則回,不是全部改完才一起回', () => { + assert.match(steps, /不要全部改完才一起回/); + assert.match(steps, /中途斷掉/); +}); + +test('三類與 --kind 的對應寫出來了,並警告 id 各自獨立', () => { + assert.match(steps, /行內.*inline/); + assert.match(steps, /一般.*general/); + assert.match(steps, /總評.*review/); + assert.match(steps, /id 各自獨立/); +}); + +test('回覆要說出做了什麼,且決定不改的也要回', () => { + assert.match(steps, /不是「已修正」/); + assert.match(steps, /決定不改的也要回/); + assert.match(steps, /沉默會讓 reviewer 以為被忽略/); +}); + +test('回覆失敗就不標記的理由有寫', () => { + assert.match(steps, /謊稱處理過/); +}); + +test('寫入前要求先試跑', () => { + assert.match(steps, /--dry-run/); +}); + +// ── 摘要 ─────────────────────────────────────────────────────────── + +test('摘要要逐則列出,並單獨點出沒有記號的那幾則', () => { + const section = steps.slice(steps.indexOf('## 5.')); + assert.match(section, /逐則一行/); + assert.match(section, /沒有留下記號的那幾則/); + assert.match(section, /以為它們被跳過/, '要說出為什麼得單獨列'); +}); + +test('摘要不自動張貼', () => { + assert.match(steps, /不自動張貼/); +}); + +// ── 邊界 ─────────────────────────────────────────────────────────── + +test('邊界列出不做的事,含不動 review 狀態', () => { + const boundary = prompt.slice(prompt.indexOf('## 邊界')); + assert.match(boundary, /不改與留言無關的程式碼/); + assert.match(boundary, /不跳過任何一則留言/); + assert.match(boundary, /不自動張貼修正摘要/); + assert.match(boundary, /不動 PR 的 review 狀態/); +});