import test from 'node:test'; import assert from 'node:assert/strict'; import { readReference, readTemplate } from './helpers/prompt-doc.js'; const rules = readReference('delivery-types'); const template = readTemplate('requirement-issue'); const TYPES = [ '需求描述概要', 'WBS(工作分解結構)', '流程圖', '甘特圖', 'PERT 圖', '關鍵路徑圖', 'API 契約文件', ]; function sectionOf(text, heading) { const lines = text.split('\n'); const start = lines.findIndex((line) => line.replace(/^### (?:\d+\. )?/, '') === heading); assert.notEqual(start, -1, `規則正本缺少「${heading}」`); const rest = lines.slice(start + 1); const end = rest.findIndex((line) => line.startsWith('### ')); return (end === -1 ? rest : rest.slice(0, end)).join('\n'); } test('需求模板以文件取代流程圖,且保留固定段落順序', () => { const headings = [...template.matchAll(/^## (.+)$/gm)].map((match) => match[1]); assert.deepEqual(headings, [ '總覽', '背景', '目標', '非目標', '領域名詞表', '文件', '驗收標準', '影響範圍', '未決事項', ]); assert.match(template, /\{\{文件\}\}/); assert.equal(template.includes('## 流程圖'), false); }); test('規則正本逐一交代七種文件的必要內容、產出位置與 ELI5 變體', () => { assert.match(rules, /^## 七種交付類型$/m); for (const type of TYPES) { const section = sectionOf(rules, type); assert.match(section, /必要內容/); assert.match(section, /產出位置/); assert.match(section, /ELI5 變體/); } }); test('API 契約規則禁止寫入目標專案,且摘要可由來源重產', () => { const section = sectionOf(rules, 'API 契約文件'); assert.match(section, /禁止把 API 契約文件寫入目標專案 repo/); assert.match(rules, /摘要可由同一份來源重新產生/); }); test('交付文件共通規則保留逐一確認與預覽能力分流', () => { assert.match(rules, /逐一確認/); assert.match(rules, /可開啟、可分享的預覽/); assert.match(rules, /沒有預覽能力時依使用者確認的方式交付/); });