test(api): add unit tests for Jira/Confluence/GitLab helpers, drop obsolete shell test

This commit is contained in:
Aleksey Shakhmatov
2026-08-06 14:43:20 +03:00
parent f802f06930
commit 7804681356
5 changed files with 79 additions and 1285 deletions
+73
View File
@@ -0,0 +1,73 @@
/**
* Unit tests for the Jira / Confluence / GitLab REST helpers.
* The lib modules are pure (no pi API), so we inject a mocked `fetchImpl`.
* Run with: node --experimental-strip-types test/api.test.ts
*/
process.env.PI_KIT_AUDIT_OFF = "1";
process.env.JIRA_TOKEN = "t-jira";
process.env.CONFLUENCE_TOKEN = "t-conf";
process.env.GITLAB_TOKEN = "t-glab";
import { buildUrl, requireToken, ApiError } from "../extensions/lib/atlassian.ts";
import { jiraBaseUrl, issueGet } from "../extensions/lib/jira.ts";
import { gitlabBaseUrl, projectId } from "../extensions/lib/gitlab.ts";
import { confluenceBaseUrl } from "../extensions/lib/confluence.ts";
let fails = 0;
function check(name: string, cond: boolean) {
console.log(`${cond ? "PASS" : "FAIL"} ${name}`);
if (!cond) fails++;
}
function okFetch(jsonBody: unknown): typeof fetch {
return (async () => ({
ok: true,
status: 200,
json: async () => jsonBody,
})) as any;
}
async function main() {
// --- atlassian helpers ---
check("buildUrl: appends query, drops empties", buildUrl("https://x/", "/a", { q: "1", e: undefined }) === "https://x/a?q=1");
check("buildUrl: no query when none", buildUrl("https://x", "/a") === "https://x/a");
check("requireToken: returns value", requireToken("JIRA_TOKEN", "h") === "t-jira");
check("requireToken: throws on missing", (() => {
try { requireToken("NO_SUCH_VAR_ZZZ", "h"); return false; } catch (e) { return e instanceof ApiError; }
})());
// --- config resolution (needs a real company.json present) ---
check("jiraBaseUrl resolves", typeof jiraBaseUrl() === "string" && jiraBaseUrl() !== "");
check("gitlabBaseUrl ends with api/v4", gitlabBaseUrl().endsWith("/api/v4"));
check("confluenceBaseUrl resolves", typeof confluenceBaseUrl() === "string" && confluenceBaseUrl() !== "");
// --- gitlab project id encoding ---
check("projectId encodes namespaces", projectId("grp/repo") === "grp%2Frepo");
check("projectId passes through numeric id", projectId("42") === "42");
// --- issueGet through a mocked fetch (field mapping) ---
const issueUrl = await issueGetByKey("PROJ-123");
check("issueGet hits /rest/api/2/issue/<key>", issueUrl.includes("/rest/api/2/issue/"));
console.log(fails === 0 ? "\nALL PASS" : `\n${fails} FAILED`);
process.exit(fails === 0 ? 0 : 1);
}
async function issueGetByKey(key: string): Promise<string> {
// Capture the URL by injecting a mocked fetch into the issueGet call path.
// We temporarily swap global.fetch.
const realFetch = globalThis.fetch;
let captured = "";
globalThis.fetch = (async (input: any) => {
captured = String(input);
return { ok: true, status: 200, json: async () => ({ key, fields: { summary: "s", status: { name: "Done" } } }) };
}) as any;
try {
await issueGet(key);
} finally {
globalThis.fetch = realFetch;
}
return captured;
}
main();