import test from "node:test"; import assert from "node:assert/strict"; import { createTempWorkspace, jsonResponse, runCli } from "./helpers.js"; const baseEnv = { ATLASSIAN_BASE_URL: "https://example.atlassian.net", ATLASSIAN_EMAIL: "dev@example.com", ATLASSIAN_API_TOKEN: "secret-token", }; test("conf-search uses CQL search and normalizes page results", async () => { const calls: Array<{ url: string; init: RequestInit | undefined }> = []; const fetchImpl: typeof fetch = async (input, init) => { calls.push({ url: typeof input === "string" ? input : input.toString(), init }); return jsonResponse({ results: [ { content: { id: "123", type: "page", title: "Runbook", _links: { webui: "/spaces/OPS/pages/123/Runbook" }, }, excerpt: "Operational runbook", }, ], start: 5, limit: 1, size: 1, totalSize: 7, }); }; const result = await runCli({ args: ["conf-search", "--query", "title ~ \"Runbook\"", "--max-results", "1", "--start-at", "5"], env: baseEnv, fetchImpl, }); assert.equal(calls.length, 1); assert.equal( calls[0]?.url, "https://example.atlassian.net/wiki/rest/api/search?cql=title+%7E+%22Runbook%22&limit=1&start=5", ); assert.equal(calls[0]?.init?.method, "GET"); assert.deepEqual(JSON.parse(result.stdout), { ok: true, data: { pages: [ { id: "123", title: "Runbook", type: "page", excerpt: "Operational runbook", url: "https://example.atlassian.net/spaces/OPS/pages/123/Runbook", }, ], startAt: 5, maxResults: 1, total: 7, }, }); }); test("conf-get returns normalized page details plus raw payload", async () => { const rawPage = { id: "123", status: "current", title: "Runbook", spaceId: "OPS", version: { number: 4 }, body: { storage: { value: "
Runbook
", representation: "storage", }, }, _links: { webui: "/spaces/OPS/pages/123/Runbook", }, }; const result = await runCli({ args: ["conf-get", "--page", "123"], env: baseEnv, fetchImpl: async () => jsonResponse(rawPage), }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, data: { page: { id: "123", title: "Runbook", type: "page", status: "current", spaceId: "OPS", version: 4, body: "Runbook
", url: "https://example.atlassian.net/spaces/OPS/pages/123/Runbook", }, }, raw: rawPage, }); }); test("conf-children returns normalized direct children with pagination", async () => { const result = await runCli({ args: ["conf-children", "--page", "123", "--max-results", "2", "--start-at", "1"], env: baseEnv, fetchImpl: async (input) => { const url = typeof input === "string" ? input : input.toString(); assert.equal( url, "https://example.atlassian.net/wiki/api/v2/pages/123/direct-children?limit=2&cursor=1", ); return jsonResponse({ results: [ { id: "124", title: "Child page", type: "page", status: "current", spaceId: "OPS", _links: { webui: "/spaces/OPS/pages/124/Child+page" }, }, ], }); }, }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, data: { pages: [ { id: "124", title: "Child page", type: "page", status: "current", spaceId: "OPS", url: "https://example.atlassian.net/spaces/OPS/pages/124/Child+page", }, ], nextCursor: null, }, }); }); test("conf-create dry-run emits a storage-format request body", async () => { const workspace = createTempWorkspace(); try { workspace.write("page.storage.html", "Runbook
"); const result = await runCli({ args: [ "conf-create", "--title", "Runbook", "--body-file", "page.storage.html", "--dry-run", ], cwd: workspace.cwd, env: { ...baseEnv, ATLASSIAN_DEFAULT_SPACE: "OPS", }, }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, dryRun: true, data: { method: "POST", url: "https://example.atlassian.net/wiki/api/v2/pages", body: { spaceId: "OPS", title: "Runbook", status: "current", body: { representation: "storage", value: "Runbook
", }, }, }, }); } finally { workspace.cleanup(); } }); test("conf-update fetches the current page version and increments it for dry-run", async () => { const workspace = createTempWorkspace(); const calls: Array<{ url: string; init: RequestInit | undefined }> = []; try { workspace.write("page.storage.html", "Updated
"); const result = await runCli({ args: [ "conf-update", "--page", "123", "--title", "Runbook", "--body-file", "page.storage.html", "--dry-run", ], cwd: workspace.cwd, env: baseEnv, fetchImpl: async (input, init) => { calls.push({ url: typeof input === "string" ? input : input.toString(), init }); return jsonResponse({ id: "123", spaceId: "OPS", status: "current", title: "Runbook", version: { number: 4 }, body: { storage: { value: "Old
", representation: "storage", }, }, }); }, }); assert.equal(calls.length, 1); assert.equal( calls[0]?.url, "https://example.atlassian.net/wiki/api/v2/pages/123?body-format=storage", ); assert.deepEqual(JSON.parse(result.stdout), { ok: true, dryRun: true, data: { method: "PUT", url: "https://example.atlassian.net/wiki/api/v2/pages/123", body: { id: "123", status: "current", title: "Runbook", spaceId: "OPS", version: { number: 5, }, body: { representation: "storage", value: "Updated
", }, }, }, }); } finally { workspace.cleanup(); } }); test("conf-comment dry-run targets footer comments", async () => { const workspace = createTempWorkspace(); try { workspace.write("comment.storage.html", "Looks good
"); const result = await runCli({ args: ["conf-comment", "--page", "123", "--body-file", "comment.storage.html", "--dry-run"], cwd: workspace.cwd, env: baseEnv, }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, dryRun: true, data: { method: "POST", url: "https://example.atlassian.net/wiki/api/v2/footer-comments", body: { pageId: "123", body: { representation: "storage", value: "Looks good
", }, }, }, }); } finally { workspace.cleanup(); } }); test("conf-update surfaces version conflicts clearly", async () => { const workspace = createTempWorkspace(); try { workspace.write("page.storage.html", "Updated
"); await assert.rejects( runCli({ args: [ "conf-update", "--page", "123", "--title", "Runbook", "--body-file", "page.storage.html", ], cwd: workspace.cwd, env: baseEnv, fetchImpl: async (input, init) => { const url = typeof input === "string" ? input : input.toString(); if (url.endsWith("?body-format=storage")) { return jsonResponse({ id: "123", spaceId: "OPS", status: "current", title: "Runbook", version: { number: 4 }, body: { storage: { value: "Old
", representation: "storage", }, }, }); } assert.equal(init?.method, "PUT"); return new Response(JSON.stringify({ message: "Conflict" }), { status: 409, statusText: "Conflict", headers: { "content-type": "application/json" }, }); }, }), /Confluence update conflict: page 123 was updated by someone else/, ); } finally { workspace.cleanup(); } });