import fs from 'node:fs'; const html = fs.readFileSync(new URL('./index.html', import.meta.url).pathname,'utf8'); // 抽出 safeJson 與 friendlyErr 求值 const grab = (name) => { const i = html.indexOf(`function ${name}(`); if (i < 0) throw new Error(`找不到 ${name}`); let d=0, j=html.indexOf('{', i); for (let k=j;k{c?(console.log('PASS:',l),pass++):(console.log('FAIL:',l,e),fail++)}; // ① safeJson:非 JSON 不可拋例外(同事撞到的 404 HTML 頁) const html404 = '404 Not Found'; await fn.safeJson({ text: () => Promise.resolve(html404) }) .then(d => t('404 HTML → 回空物件不拋錯', typeof d === 'object' && d !== null)) .catch(e => t('404 HTML → 不該拋錯', false, e.message)); await fn.safeJson({ text: () => Promise.resolve('') }) .then(d => t('空回應 → 回空物件', JSON.stringify(d)==='{}')) .catch(() => t('空回應 → 不該拋錯', false)); await fn.safeJson({ text: () => Promise.resolve('{"error":"帳號或密碼不對"}') }) .then(d => t('正常 JSON 仍要解析得出來', d.error === '帳號或密碼不對'), ) .catch(() => t('正常 JSON 不該拋錯', false)); // ② friendlyErr:不可把技術訊息噴給使用者 const leak = fn.friendlyErr(new Error('Unexpected non-whitespace character after JSON at position 4')); t('JSON 錯誤 → 不外洩原文', !/JSON|position/i.test(leak), `實得: ${leak}`); t('JSON 錯誤 → 說人話', /伺服器回應異常/.test(leak), `實得: ${leak}`); const net = fn.friendlyErr(new Error('Failed to fetch')); t('網路錯誤 → 既有訊息保留', /連線中斷/.test(net), `實得: ${net}`); const ours = fn.friendlyErr(new Error('帳號或密碼不對——用你在知識庫網站設定的那組')); t('我們自己的中文訊息 → 原樣顯示', /帳號或密碼不對/.test(ours), `實得: ${ours}`); const stack = fn.friendlyErr(new Error('TypeError: Cannot read properties of undefined')); t('英文技術訊息 → 收斂不外洩', !/TypeError|undefined/.test(stack), `實得: ${stack}`); console.log(`\n=== ${pass} passed, ${fail} failed ===`); process.exit(fail?1:0);