194 lines
6.1 KiB
TypeScript
194 lines
6.1 KiB
TypeScript
import { describe, it, afterEach } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const originalFetch = globalThis.fetch;
|
|
|
|
function mockFetchJson(data, status = 200) {
|
|
globalThis.fetch = async () => ({ ok: status === 200, status, json: async () => data });
|
|
}
|
|
|
|
function mockFetchText(text, status = 200) {
|
|
globalThis.fetch = async () => ({ ok: status === 200, status, text: async () => text });
|
|
}
|
|
|
|
afterEach(() => {
|
|
globalThis.fetch = originalFetch;
|
|
});
|
|
|
|
describe("releaseChecker", () => {
|
|
let mod;
|
|
|
|
it("should load module", async () => {
|
|
mod = await import("../../src/lib/versionManager/releaseChecker.ts");
|
|
assert.ok(mod.getLatestRelease);
|
|
assert.ok(mod.getReleaseByVersion);
|
|
assert.ok(mod.getAvailableVersions);
|
|
assert.ok(mod.getChecksums);
|
|
assert.ok(mod.clearCache);
|
|
});
|
|
|
|
describe("getLatestRelease", () => {
|
|
it("should parse latest release from GitHub API", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({
|
|
tag_name: "v6.9.7",
|
|
published_at: "2025-01-01T00:00:00Z",
|
|
body: "notes",
|
|
assets: [{ name: "a.tar.gz", browser_download_url: "https://x.com/a.tar.gz", size: 100 }],
|
|
});
|
|
const r = await mod.getLatestRelease();
|
|
assert.equal(r.tag, "v6.9.7");
|
|
assert.equal(r.version, "6.9.7");
|
|
assert.equal(r.publishedAt, "2025-01-01T00:00:00Z");
|
|
assert.equal(r.body, "notes");
|
|
assert.equal(r.assets.length, 1);
|
|
assert.equal(r.assets[0].name, "a.tar.gz");
|
|
assert.equal(r.assets[0].url, "https://x.com/a.tar.gz");
|
|
assert.equal(r.assets[0].size, 100);
|
|
});
|
|
|
|
it("should handle empty assets", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v1.0.0", published_at: "", body: "", assets: [] });
|
|
const r = await mod.getLatestRelease();
|
|
assert.equal(r.assets.length, 0);
|
|
});
|
|
|
|
it("should handle null body", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v1.0.0", published_at: "", body: null, assets: [] });
|
|
const r = await mod.getLatestRelease();
|
|
assert.equal(r.body, "");
|
|
});
|
|
|
|
it("should handle missing assets array", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v1.0.0", published_at: "", body: "" });
|
|
const r = await mod.getLatestRelease();
|
|
assert.equal(r.assets.length, 0);
|
|
});
|
|
|
|
it("should throw on non-ok response", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({}, 404);
|
|
await assert.rejects(() => mod.getLatestRelease(), { message: /GitHub API 404/ });
|
|
});
|
|
});
|
|
|
|
describe("getReleaseByVersion", () => {
|
|
it("should fetch a specific version", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v6.9.0", published_at: "", body: "", assets: [] });
|
|
const r = await mod.getReleaseByVersion("6.9.0");
|
|
assert.ok(r);
|
|
assert.equal(r.version, "6.9.0");
|
|
});
|
|
|
|
it("should prepend v if missing", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v6.9.0", published_at: "", body: "", assets: [] });
|
|
const r = await mod.getReleaseByVersion("6.9.0");
|
|
assert.ok(r);
|
|
});
|
|
|
|
it("should return null on 404", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({}, 404);
|
|
const r = await mod.getReleaseByVersion("999.0.0");
|
|
assert.equal(r, null);
|
|
});
|
|
|
|
it("should return null on network error", async () => {
|
|
mod.clearCache();
|
|
globalThis.fetch = async () => {
|
|
throw new Error("Network error");
|
|
};
|
|
const r = await mod.getReleaseByVersion("999.0.0");
|
|
assert.equal(r, null);
|
|
});
|
|
});
|
|
|
|
describe("getAvailableVersions", () => {
|
|
it("should return version tags", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson([{ tag_name: "v6.9.7" }, { tag_name: "v6.9.6" }]);
|
|
const v = await mod.getAvailableVersions();
|
|
assert.deepEqual(v, ["v6.9.7", "v6.9.6"]);
|
|
});
|
|
|
|
it("should handle empty array", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson([]);
|
|
const v = await mod.getAvailableVersions();
|
|
assert.deepEqual(v, []);
|
|
});
|
|
|
|
it("should handle non-array response", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ message: "not array" });
|
|
const v = await mod.getAvailableVersions();
|
|
assert.deepEqual(v, []);
|
|
});
|
|
});
|
|
|
|
describe("getChecksums", () => {
|
|
it("should parse checksums.txt", async () => {
|
|
mod.clearCache();
|
|
mockFetchText("abc123 file.tar.gz\n456def other.tar.gz\n");
|
|
const c = await mod.getChecksums("6.9.7");
|
|
assert.equal(c.size, 2);
|
|
assert.equal(c.get("file.tar.gz"), "abc123");
|
|
assert.equal(c.get("other.tar.gz"), "456def");
|
|
});
|
|
|
|
it("should return empty map on 404", async () => {
|
|
mod.clearCache();
|
|
mockFetchText("not found", 404);
|
|
const c = await mod.getChecksums("999.0.0");
|
|
assert.equal(c.size, 0);
|
|
});
|
|
|
|
it("should return empty map on error", async () => {
|
|
mod.clearCache();
|
|
globalThis.fetch = async () => {
|
|
throw new Error("fail");
|
|
};
|
|
const c = await mod.getChecksums("999.0.0");
|
|
assert.equal(c.size, 0);
|
|
});
|
|
});
|
|
|
|
describe("clearCache", () => {
|
|
it("should clear cache so next call fetches fresh data", async () => {
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v6.9.7", published_at: "", body: "", assets: [] });
|
|
const r1 = await mod.getLatestRelease();
|
|
assert.equal(r1.version, "6.9.7");
|
|
|
|
mod.clearCache();
|
|
mockFetchJson({ tag_name: "v6.9.8", published_at: "", body: "", assets: [] });
|
|
const r2 = await mod.getLatestRelease();
|
|
assert.equal(r2.version, "6.9.8");
|
|
});
|
|
});
|
|
|
|
describe("cache behavior", () => {
|
|
it("should cache responses within TTL", async () => {
|
|
mod.clearCache();
|
|
let callCount = 0;
|
|
globalThis.fetch = async () => {
|
|
callCount++;
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
json: async () => ({ tag_name: "v6.9.7", published_at: "", body: "", assets: [] }),
|
|
};
|
|
};
|
|
await mod.getLatestRelease();
|
|
assert.equal(callCount, 1);
|
|
await mod.getLatestRelease();
|
|
assert.equal(callCount, 1); // cached
|
|
});
|
|
});
|
|
});
|