test(calculate-version): 新增 version/config/releases 單元測試
以 node:test 為 app/ 模組補上 24 個單元測試,涵蓋版本計算、設定載入與 release 分頁抓取。 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
bd6b6017ab
commit
923c94d198
@@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const { fetchReleases } = require('../app/releases');
|
||||
|
||||
// 以可控的假回應替換全域 fetch,並於結束後還原
|
||||
function withFetch(handler, run) {
|
||||
const original = globalThis.fetch;
|
||||
globalThis.fetch = handler;
|
||||
return Promise.resolve()
|
||||
.then(run)
|
||||
.finally(() => {
|
||||
globalThis.fetch = original;
|
||||
});
|
||||
}
|
||||
|
||||
// 建立模擬 Response 物件
|
||||
const jsonResponse = (body, ok = true) => ({
|
||||
ok,
|
||||
text: async () => (typeof body === 'string' ? body : JSON.stringify(body)),
|
||||
});
|
||||
|
||||
test('fetchReleases 單頁(不足一頁即停止)', async () => {
|
||||
await withFetch(
|
||||
async () => jsonResponse([{ tag_name: 'v1.0.0' }]),
|
||||
async () => {
|
||||
const releases = await fetchReleases('https://gitea.example.com/api');
|
||||
assert.deepEqual(releases, [{ tag_name: 'v1.0.0' }]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('fetchReleases 跨頁合併直到不足一頁', async () => {
|
||||
const pages = {
|
||||
1: Array.from({ length: 10 }, (_, i) => ({ tag_name: `v1.0.${i}` })),
|
||||
2: [{ tag_name: 'v1.1.0' }],
|
||||
};
|
||||
const seen = [];
|
||||
|
||||
await withFetch(
|
||||
async (url) => {
|
||||
const page = Number(new URL(url).searchParams.get('page'));
|
||||
seen.push(page);
|
||||
return jsonResponse(pages[page]);
|
||||
},
|
||||
async () => {
|
||||
const releases = await fetchReleases('https://gitea.example.com/api');
|
||||
assert.equal(releases.length, 11);
|
||||
assert.deepEqual(seen, [1, 2]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('fetchReleases 對非 2xx 回應拋錯', async () => {
|
||||
await withFetch(
|
||||
async () => jsonResponse('Not Found', false),
|
||||
async () => {
|
||||
await assert.rejects(
|
||||
() => fetchReleases('https://gitea.example.com/api'),
|
||||
/release API 請求失敗/,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('fetchReleases 對非陣列回應拋錯', async () => {
|
||||
await withFetch(
|
||||
async () => jsonResponse({ message: 'oops' }),
|
||||
async () => {
|
||||
await assert.rejects(
|
||||
() => fetchReleases('https://gitea.example.com/api'),
|
||||
/回傳非陣列資料/,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('fetchReleases 有 token 時帶入授權標頭', async () => {
|
||||
let captured;
|
||||
|
||||
await withFetch(
|
||||
async (url, options) => {
|
||||
captured = options;
|
||||
return jsonResponse([]);
|
||||
},
|
||||
async () => {
|
||||
await fetchReleases('https://gitea.example.com/api', { token: 'secret' });
|
||||
assert.equal(captured.headers.Authorization, 'token secret');
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user