test(release-cleanup): 補上結束碼、sanitizeBody 與 logger 輸出測試
新增子行程驗證 index.js 失敗時以非零狀態結束、fetchAllPages 錯誤訊息 清理控制字元與長度限制、以及 logger 各輸出函式格式與 stdout/stderr 分流測試。 測試共 56 項全數通過。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
87db9030d6
commit
826b559006
@@ -122,6 +122,26 @@ test('fetchAllPages 在頁數超過 MAX_PAGES 時中止以避免無限迴圈', a
|
||||
)
|
||||
})
|
||||
|
||||
test('fetchAllPages 的錯誤訊息會清理控制字元並限制長度(sanitizeBody)', async () => {
|
||||
const nasty = 'line1\nline2\r\tinjected' + 'x'.repeat(500)
|
||||
globalThis.fetch = async () => ({
|
||||
ok: false,
|
||||
status: 500,
|
||||
text: async () => nasty,
|
||||
})
|
||||
const client = new GiteaClient({})
|
||||
let message = ''
|
||||
try {
|
||||
await client.fetchAllPages('https://example.com/api')
|
||||
} catch (error) {
|
||||
message = error.message
|
||||
}
|
||||
// 控制字元(換行、Tab 等)已被移除
|
||||
assert.doesNotMatch(message, /[\u0000-\u001F]/)
|
||||
// 回應內容片段受 200 字元上限約束(原始有 500 個 x)
|
||||
assert.ok((message.match(/x/g) || []).length <= 200)
|
||||
})
|
||||
|
||||
test('deleteResource 回傳 HTTP 狀態碼', async () => {
|
||||
globalThis.fetch = async (url, opts) => {
|
||||
assert.equal(opts.method, 'DELETE')
|
||||
|
||||
+55
-1
@@ -1,11 +1,65 @@
|
||||
import { test, afterEach } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { failError } from '../logger.js'
|
||||
import {
|
||||
separator,
|
||||
section,
|
||||
info,
|
||||
success,
|
||||
warn,
|
||||
fail,
|
||||
failError,
|
||||
} from '../logger.js'
|
||||
|
||||
const realWrite = process.stderr.write
|
||||
const realStdoutWrite = process.stdout.write
|
||||
|
||||
afterEach(() => {
|
||||
process.stderr.write = realWrite
|
||||
process.stdout.write = realStdoutWrite
|
||||
})
|
||||
|
||||
// 攔截寫入 stdout 的內容
|
||||
function captureStdout(fn) {
|
||||
const chunks = []
|
||||
process.stdout.write = (chunk) => {
|
||||
chunks.push(String(chunk))
|
||||
return true
|
||||
}
|
||||
try {
|
||||
fn()
|
||||
} finally {
|
||||
process.stdout.write = realStdoutWrite
|
||||
}
|
||||
return chunks.join('')
|
||||
}
|
||||
|
||||
test('info/success/warn 以正確前綴寫入 stdout', () => {
|
||||
assert.equal(captureStdout(() => info('hi')), '[INFO] hi\n')
|
||||
assert.equal(captureStdout(() => success('ok')), '[OK] ok\n')
|
||||
assert.equal(captureStdout(() => warn('careful')), '[WARN] careful\n')
|
||||
})
|
||||
|
||||
test('separator 輸出等號分隔線', () => {
|
||||
const out = captureStdout(() => separator())
|
||||
assert.match(out, /^\n={50}\n$/)
|
||||
})
|
||||
|
||||
test('section 輸出分隔線、標題與虛線', () => {
|
||||
const out = captureStdout(() => section('參數檢查'))
|
||||
assert.match(out, /={50}\n參數檢查\n-{50}\n/)
|
||||
})
|
||||
|
||||
test('fail 寫入 stderr 而非 stdout', () => {
|
||||
const stdout = captureStdout(() => {
|
||||
const chunks = []
|
||||
process.stderr.write = (chunk) => {
|
||||
chunks.push(String(chunk))
|
||||
return true
|
||||
}
|
||||
fail('boom')
|
||||
assert.equal(chunks.join(''), '[ERR] boom\n')
|
||||
})
|
||||
assert.equal(stdout, '') // fail 不應寫入 stdout
|
||||
})
|
||||
|
||||
// 攔截寫入 stderr 的內容
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { test, afterEach } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { main } from '../index.js'
|
||||
|
||||
const realFetch = globalThis.fetch
|
||||
@@ -41,3 +43,14 @@ test('main 在必填環境變數缺失時 reject(供整合層級驗證錯誤處
|
||||
})
|
||||
await assert.rejects(() => main(), /GITEA_SERVER_URL is required/)
|
||||
})
|
||||
|
||||
test('直接執行 index.js 在設定錯誤時以非零狀態碼結束', () => {
|
||||
const indexPath = fileURLToPath(new URL('../index.js', import.meta.url))
|
||||
// 僅帶 PATH,不提供任何必填環境變數,使 main 拋錯並觸發 process.exit(1)
|
||||
const result = spawnSync(process.execPath, [indexPath], {
|
||||
env: { PATH: process.env.PATH },
|
||||
encoding: 'utf8',
|
||||
})
|
||||
assert.equal(result.status, 1)
|
||||
assert.match(result.stderr, /GITEA_SERVER_URL is required/)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user