diff --git a/pr-checks/post-comment.test.ts b/pr-checks/post-comment.test.ts index 492c45f34..db6d45539 100644 --- a/pr-checks/post-comment.test.ts +++ b/pr-checks/post-comment.test.ts @@ -10,7 +10,9 @@ import { describe, it } from "node:test"; import { type ApiClient } from "./api-client"; import { findExistingComment, + type Options, parseOptions, + performAction, resolveToken, } from "./post-comment"; @@ -211,3 +213,87 @@ describe("findExistingComment", async () => { assert.equal(id, undefined); }); }); + +/** A baseline set of `Options`, for use in `performAction` tests. */ +const baseOptions: Options = { + body: "hello", + marker: "", + actionCondition: true, + actionIfTrue: "insert", + actionIfFalse: "delete", + issueId: 42, + repository: { owner: "owner", repo: "repo" }, +}; + +describe("performAction", async () => { + await it("does nothing for 'none'", async () => { + const { client, calls } = fakeClient([]); + await performAction(client, "none", baseOptions); + assert.deepEqual(calls, { + createComment: [], + updateComment: [], + deleteComment: [], + }); + }); + + await it("creates a new comment for 'insert', with the marker prepended", async () => { + const { client, calls } = fakeClient([]); + await performAction(client, "insert", baseOptions); + assert.deepEqual(calls.createComment, [ + { + owner: "owner", + repo: "repo", + issue_number: 42, + body: "\nhello", + }, + ]); + assert.deepEqual(calls.updateComment, []); + assert.deepEqual(calls.deleteComment, []); + }); + + await it("creates a new comment for 'upsert' when no existing comment is found", async () => { + const { client, calls } = fakeClient([{ id: 1, body: "unrelated" }]); + await performAction(client, "upsert", baseOptions); + assert.deepEqual(calls.createComment, [ + { + owner: "owner", + repo: "repo", + issue_number: 42, + body: "\nhello", + }, + ]); + assert.deepEqual(calls.updateComment, []); + }); + + await it("updates the existing comment for 'upsert' when one is found", async () => { + const { client, calls } = fakeClient([ + { id: 7, body: "\nold" }, + ]); + await performAction(client, "upsert", baseOptions); + assert.deepEqual(calls.updateComment, [ + { + owner: "owner", + repo: "repo", + comment_id: 7, + body: "\nhello", + }, + ]); + assert.deepEqual(calls.createComment, []); + }); + + await it("does nothing for 'delete' when no existing comment is found", async () => { + const { client, calls } = fakeClient([{ id: 1, body: "unrelated" }]); + await performAction(client, "delete", baseOptions); + assert.deepEqual(calls.deleteComment, []); + }); + + await it("deletes the existing comment for 'delete' when one is found", async () => { + const { client, calls } = fakeClient([ + { id: 9, body: "\nold" }, + ]); + await performAction(client, "delete", baseOptions); + assert.deepEqual(calls.deleteComment, [ + { owner: "owner", repo: "repo", comment_id: 9 }, + ]); + }); +}); diff --git a/pr-checks/post-comment.ts b/pr-checks/post-comment.ts index 01b36cac7..6c1a1e5e5 100644 --- a/pr-checks/post-comment.ts +++ b/pr-checks/post-comment.ts @@ -172,16 +172,17 @@ export async function findExistingComment( return comments.find((comment) => comment.body?.startsWith(marker))?.id; } -async function main(): Promise { - const options = parseOptions(); - const action = options.actionCondition - ? options.actionIfTrue - : options.actionIfFalse; - console.info(`Resolved action: ${action}`); - - const token = resolveToken(process.env); +/** + * Performs the resolved `action` against a (possibly pre-existing) marked comment, using + * `client` to talk to the GitHub API. This is the core dispatch logic of this script, extracted + * from `main` so it can be unit-tested with an injected (fake) `client`. + */ +export async function performAction( + client: ApiClient, + action: Action, + options: Options, +): Promise { const { issueId, marker, repository } = options; - const client = getApiClient(token); const body = `${marker}\n${options.body}`; let existingCommentId: number | undefined; @@ -235,6 +236,19 @@ async function main(): Promise { } break; } +} + +async function main(): Promise { + const options = parseOptions(); + const action = options.actionCondition + ? options.actionIfTrue + : options.actionIfFalse; + console.info(`Resolved action: ${action}`); + + const token = resolveToken(process.env); + const client = getApiClient(token); + + await performAction(client, action, options); return 0; }