import test from "node:test"; import assert from "node:assert/strict"; import { markdownToAdf } from "../src/adf.js"; 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("jira-search emits normalized results and uses pagination inputs", async () => { const calls: Array<{ url: string; init: RequestInit | undefined }> = []; const fetchImpl: typeof fetch = async (input, init) => { const url = typeof input === "string" ? input : input.toString(); calls.push({ url, init }); return jsonResponse({ startAt: 10, maxResults: 2, total: 25, issues: [ { key: "ENG-1", fields: { summary: "Add Jira search command", issuetype: { name: "Story" }, status: { name: "In Progress" }, assignee: { displayName: "Ada Lovelace" }, created: "2026-03-01T00:00:00.000Z", updated: "2026-03-02T00:00:00.000Z", }, }, ], }); }; const result = await runCli({ args: ["jira-search", "--jql", "project = ENG", "--max-results", "2", "--start-at", "10"], env: baseEnv, fetchImpl, }); assert.equal(calls.length, 1); assert.equal(calls[0]?.url, "https://example.atlassian.net/rest/api/3/search"); assert.equal(calls[0]?.init?.method, "POST"); assert.match(String(calls[0]?.init?.headers), /Authorization/); assert.deepEqual(JSON.parse(String(calls[0]?.init?.body)), { jql: "project = ENG", maxResults: 2, startAt: 10, fields: ["summary", "issuetype", "status", "assignee", "created", "updated"], }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, data: { issues: [ { key: "ENG-1", summary: "Add Jira search command", issueType: "Story", status: "In Progress", assignee: "Ada Lovelace", created: "2026-03-01T00:00:00.000Z", updated: "2026-03-02T00:00:00.000Z", url: "https://example.atlassian.net/browse/ENG-1", }, ], startAt: 10, maxResults: 2, total: 25, }, }); }); test("jira-get returns normalized fields plus the raw Jira payload", async () => { const rawIssue = { key: "ENG-42", fields: { summary: "Ship v1", issuetype: { name: "Task" }, status: { name: "Done" }, assignee: { displayName: "Grace Hopper" }, created: "2026-03-03T00:00:00.000Z", updated: "2026-03-04T00:00:00.000Z", }, }; const fetchImpl: typeof fetch = async () => jsonResponse(rawIssue); const result = await runCli({ args: ["jira-get", "--issue", "ENG-42"], env: baseEnv, fetchImpl, }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, data: { issue: { key: "ENG-42", summary: "Ship v1", issueType: "Task", status: "Done", assignee: "Grace Hopper", created: "2026-03-03T00:00:00.000Z", updated: "2026-03-04T00:00:00.000Z", url: "https://example.atlassian.net/browse/ENG-42", }, }, raw: rawIssue, }); }); test("markdownToAdf converts headings, paragraphs, and bullet lists", () => { assert.deepEqual(markdownToAdf("# Summary\n\nBuild the Jira skill.\n\n- Search\n- Comment"), { type: "doc", version: 1, content: [ { type: "heading", attrs: { level: 1 }, content: [{ type: "text", text: "Summary" }], }, { type: "paragraph", content: [{ type: "text", text: "Build the Jira skill." }], }, { type: "bulletList", content: [ { type: "listItem", content: [ { type: "paragraph", content: [{ type: "text", text: "Search" }], }, ], }, { type: "listItem", content: [ { type: "paragraph", content: [{ type: "text", text: "Comment" }], }, ], }, ], }, ], }); }); test("jira-create dry-run emits an ADF request body without calling Jira", async () => { const workspace = createTempWorkspace(); try { workspace.write("description.md", "# New story\n\n- one\n- two"); let called = false; const result = await runCli({ args: [ "jira-create", "--type", "Story", "--summary", "Create the Atlassian skill", "--description-file", "description.md", "--dry-run", ], cwd: workspace.cwd, env: { ...baseEnv, ATLASSIAN_DEFAULT_PROJECT: "ENG", }, fetchImpl: async () => { called = true; return jsonResponse({}); }, }); assert.equal(called, false); assert.deepEqual(JSON.parse(result.stdout), { ok: true, dryRun: true, data: { method: "POST", url: "https://example.atlassian.net/rest/api/3/issue", body: { fields: { project: { key: "ENG" }, issuetype: { name: "Story" }, summary: "Create the Atlassian skill", description: markdownToAdf("# New story\n\n- one\n- two"), }, }, }, }); } finally { workspace.cleanup(); } }); test("jira-update, jira-comment, and jira-transition dry-runs build the expected Jira requests", async () => { const workspace = createTempWorkspace(); try { workspace.write("issue.md", "Updated description"); workspace.write("comment.md", "Comment body"); const update = await runCli({ args: [ "jira-update", "--issue", "ENG-9", "--summary", "Updated summary", "--description-file", "issue.md", "--dry-run", ], cwd: workspace.cwd, env: baseEnv, }); const comment = await runCli({ args: ["jira-comment", "--issue", "ENG-9", "--body-file", "comment.md", "--dry-run"], cwd: workspace.cwd, env: baseEnv, }); const transition = await runCli({ args: ["jira-transition", "--issue", "ENG-9", "--transition", "31", "--dry-run"], cwd: workspace.cwd, env: baseEnv, }); assert.deepEqual(JSON.parse(update.stdout), { ok: true, dryRun: true, data: { method: "PUT", url: "https://example.atlassian.net/rest/api/3/issue/ENG-9", body: { fields: { summary: "Updated summary", description: markdownToAdf("Updated description"), }, }, }, }); assert.deepEqual(JSON.parse(comment.stdout), { ok: true, dryRun: true, data: { method: "POST", url: "https://example.atlassian.net/rest/api/3/issue/ENG-9/comment", body: { body: markdownToAdf("Comment body"), }, }, }); assert.deepEqual(JSON.parse(transition.stdout), { ok: true, dryRun: true, data: { method: "POST", url: "https://example.atlassian.net/rest/api/3/issue/ENG-9/transitions", body: { transition: { id: "31", }, }, }, }); } finally { workspace.cleanup(); } }); test("jira-transitions returns normalized transition options", async () => { const fetchImpl: typeof fetch = async () => jsonResponse({ transitions: [ { id: "21", name: "Start Progress", to: { name: "In Progress" }, hasScreen: false, }, ], }); const result = await runCli({ args: ["jira-transitions", "--issue", "ENG-9"], env: baseEnv, fetchImpl, }); assert.deepEqual(JSON.parse(result.stdout), { ok: true, data: { transitions: [ { id: "21", name: "Start Progress", toStatus: "In Progress", hasScreen: false, }, ], }, }); });