Files
release-cleanup/app/test/gitea-client.test.js
T
JefferyandClaude Opus 4.8 b9d7c4e970 test(release-cleanup): 補強逾時、非陣列、token 邊界與 failError 測試
新增 fetchAllPages 的 AbortError 逾時與非陣列回應測試、loadConfig 的
GITEA_TOKEN 邊界測試,以及 logger.failError 測試。測試共 47 項全數通過。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:04:29 +08:00

123 lines
3.4 KiB
JavaScript

import { test, afterEach } from 'node:test'
import assert from 'node:assert/strict'
import { GiteaClient } from '../gitea-client.js'
const realFetch = globalThis.fetch
afterEach(() => {
globalThis.fetch = realFetch
})
// 建立模擬的 JSON 回應(含 content-type 標頭)
function jsonResponse(data) {
return {
ok: true,
status: 200,
headers: { get: () => 'application/json' },
json: async () => data,
text: async () => JSON.stringify(data),
}
}
test('建構子在有 token 時帶上 Authorization 標頭', () => {
const client = new GiteaClient({ token: 'abc' })
assert.equal(client.headers.Authorization, 'token abc')
})
test('建構子在無 token 時不帶 Authorization 標頭', () => {
const client = new GiteaClient({})
assert.equal(client.headers.Authorization, undefined)
})
test('fetchAllPages 逐頁讀取直到空陣列', async () => {
const pages = {
1: [{ id: 1 }, { id: 2 }],
2: [{ id: 3 }],
3: [],
}
const requested = []
globalThis.fetch = async (url) => {
const page = new URL(url).searchParams.get('page')
requested.push(page)
return jsonResponse(pages[page])
}
const client = new GiteaClient({})
const items = await client.fetchAllPages('https://example.com/api')
assert.deepEqual(
items.map((i) => i.id),
[1, 2, 3],
)
assert.deepEqual(requested, ['1', '2', '3'])
})
test('fetchAllPages 帶上逾時 signal', async () => {
let sawSignal = false
globalThis.fetch = async (_url, opts) => {
sawSignal = opts && typeof opts.signal === 'object' && opts.signal !== null
return jsonResponse([])
}
const client = new GiteaClient({})
await client.fetchAllPages('https://example.com/api')
assert.equal(sawSignal, true)
})
test('fetchAllPages 在 HTTP 錯誤時丟出例外', async () => {
globalThis.fetch = async () => ({
ok: false,
status: 500,
text: async () => 'boom',
})
const client = new GiteaClient({})
await assert.rejects(
() => client.fetchAllPages('https://example.com/api'),
/HTTP 500/,
)
})
test('fetchAllPages 在回應非 JSON 時丟出例外', async () => {
globalThis.fetch = async () => ({
ok: true,
status: 200,
headers: { get: () => 'text/html' },
text: async () => '<html>error</html>',
})
const client = new GiteaClient({})
await assert.rejects(
() => client.fetchAllPages('https://example.com/api'),
/non-JSON content-type/,
)
})
test('fetchAllPages 在回應為非陣列 JSON 時丟出例外', async () => {
globalThis.fetch = async () => jsonResponse({ message: 'error object' })
const client = new GiteaClient({})
await assert.rejects(
() => client.fetchAllPages('https://example.com/api'),
/non-array JSON payload/,
)
})
test('fetchAllPages 在 fetch 因逾時拋出 AbortError 時向外拋出', async () => {
globalThis.fetch = async () => {
const err = new Error('The operation was aborted due to timeout')
err.name = 'AbortError'
throw err
}
const client = new GiteaClient({})
await assert.rejects(
() => client.fetchAllPages('https://example.com/api'),
(err) => err.name === 'AbortError',
)
})
test('deleteResource 回傳 HTTP 狀態碼', async () => {
globalThis.fetch = async (url, opts) => {
assert.equal(opts.method, 'DELETE')
return { status: 204 }
}
const client = new GiteaClient({})
assert.equal(await client.deleteResource('https://example.com/api/1'), 204)
})