|
| 1 | +// @ts-check |
| 2 | +import { describe, it, expect, beforeEach, vi } from "vitest"; |
| 3 | + |
| 4 | +// messages_core.cjs calls core.warning on parse failures - provide a stub |
| 5 | +const mockCore = { |
| 6 | + info: vi.fn(), |
| 7 | + warning: vi.fn(), |
| 8 | + error: vi.fn(), |
| 9 | + setFailed: vi.fn(), |
| 10 | + setOutput: vi.fn(), |
| 11 | +}; |
| 12 | +global.core = mockCore; |
| 13 | + |
| 14 | +const { getRunStartedMessage, getRunSuccessMessage, getRunFailureMessage, getDetectionFailureMessage, getPullRequestCreatedMessage, getIssueCreatedMessage, getCommitPushedMessage } = require("./messages_run_status.cjs"); |
| 15 | + |
| 16 | +const WORKFLOW = "My Workflow"; |
| 17 | +const RUN_URL = "https://github.com/owner/repo/actions/runs/99"; |
| 18 | + |
| 19 | +describe("messages_run_status", () => { |
| 20 | + beforeEach(() => { |
| 21 | + vi.clearAllMocks(); |
| 22 | + delete process.env.GH_AW_SAFE_OUTPUT_MESSAGES; |
| 23 | + }); |
| 24 | + |
| 25 | + describe("getRunStartedMessage", () => { |
| 26 | + it("returns default template with all placeholders substituted", () => { |
| 27 | + const msg = getRunStartedMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, eventType: "issue" }); |
| 28 | + expect(msg).toBe(`🚀 [${WORKFLOW}](${RUN_URL}) has started processing this issue`); |
| 29 | + }); |
| 30 | + |
| 31 | + it("supports different event types", () => { |
| 32 | + expect(getRunStartedMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, eventType: "pull request" })).toContain("pull request"); |
| 33 | + expect(getRunStartedMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, eventType: "discussion" })).toContain("discussion"); |
| 34 | + }); |
| 35 | + |
| 36 | + it("uses custom template from config", () => { |
| 37 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ runStarted: "Custom: {workflow_name} started" }); |
| 38 | + const msg = getRunStartedMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, eventType: "issue" }); |
| 39 | + expect(msg).toBe(`Custom: ${WORKFLOW} started`); |
| 40 | + }); |
| 41 | + |
| 42 | + it("substitutes camelCase keys as well as snake_case", () => { |
| 43 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ runStarted: "{workflowName} at {runUrl}" }); |
| 44 | + const msg = getRunStartedMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, eventType: "issue" }); |
| 45 | + expect(msg).toBe(`${WORKFLOW} at ${RUN_URL}`); |
| 46 | + }); |
| 47 | + }); |
| 48 | + |
| 49 | + describe("getRunSuccessMessage", () => { |
| 50 | + it("returns default template with placeholders substituted", () => { |
| 51 | + const msg = getRunSuccessMessage({ workflowName: WORKFLOW, runUrl: RUN_URL }); |
| 52 | + expect(msg).toBe(`✅ [${WORKFLOW}](${RUN_URL}) completed successfully!`); |
| 53 | + }); |
| 54 | + |
| 55 | + it("uses custom template from config", () => { |
| 56 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ runSuccess: "Done: {workflow_name}" }); |
| 57 | + const msg = getRunSuccessMessage({ workflowName: WORKFLOW, runUrl: RUN_URL }); |
| 58 | + expect(msg).toBe(`Done: ${WORKFLOW}`); |
| 59 | + }); |
| 60 | + |
| 61 | + it("ignores unrelated config keys and uses default", () => { |
| 62 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ runStarted: "overridden" }); |
| 63 | + const msg = getRunSuccessMessage({ workflowName: WORKFLOW, runUrl: RUN_URL }); |
| 64 | + expect(msg).toContain("completed successfully"); |
| 65 | + }); |
| 66 | + }); |
| 67 | + |
| 68 | + describe("getRunFailureMessage", () => { |
| 69 | + it("returns default template with status substituted", () => { |
| 70 | + const msg = getRunFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, status: "failed" }); |
| 71 | + expect(msg).toBe(`❌ [${WORKFLOW}](${RUN_URL}) failed. Please review the logs for details.`); |
| 72 | + }); |
| 73 | + |
| 74 | + it("handles different status values", () => { |
| 75 | + expect(getRunFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, status: "was cancelled" })).toContain("was cancelled"); |
| 76 | + expect(getRunFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, status: "timed out" })).toContain("timed out"); |
| 77 | + }); |
| 78 | + |
| 79 | + it("uses custom template from config", () => { |
| 80 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ runFailure: "FAILED: {workflow_name} - {status}" }); |
| 81 | + const msg = getRunFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, status: "failed" }); |
| 82 | + expect(msg).toBe(`FAILED: ${WORKFLOW} - failed`); |
| 83 | + }); |
| 84 | + }); |
| 85 | + |
| 86 | + describe("getDetectionFailureMessage", () => { |
| 87 | + it("returns default template with placeholders substituted", () => { |
| 88 | + const msg = getDetectionFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL }); |
| 89 | + expect(msg).toBe(`⚠️ Security scanning failed for [${WORKFLOW}](${RUN_URL}). Review the logs for details.`); |
| 90 | + }); |
| 91 | + |
| 92 | + it("uses custom template from config", () => { |
| 93 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ detectionFailure: "Security alert for {workflow_name}" }); |
| 94 | + const msg = getDetectionFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL }); |
| 95 | + expect(msg).toBe(`Security alert for ${WORKFLOW}`); |
| 96 | + }); |
| 97 | + }); |
| 98 | + |
| 99 | + describe("getPullRequestCreatedMessage", () => { |
| 100 | + it("returns default template with item_number and item_url substituted", () => { |
| 101 | + const msg = getPullRequestCreatedMessage({ itemNumber: 42, itemUrl: "https://github.com/owner/repo/pull/42" }); |
| 102 | + expect(msg).toBe("Pull request created: [#42](https://github.com/owner/repo/pull/42)"); |
| 103 | + }); |
| 104 | + |
| 105 | + it("uses custom template from config", () => { |
| 106 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ pullRequestCreated: "PR #{item_number} ready" }); |
| 107 | + const msg = getPullRequestCreatedMessage({ itemNumber: 7, itemUrl: "https://github.com/owner/repo/pull/7" }); |
| 108 | + expect(msg).toBe("PR #7 ready"); |
| 109 | + }); |
| 110 | + }); |
| 111 | + |
| 112 | + describe("getIssueCreatedMessage", () => { |
| 113 | + it("returns default template with item_number and item_url substituted", () => { |
| 114 | + const msg = getIssueCreatedMessage({ itemNumber: 15, itemUrl: "https://github.com/owner/repo/issues/15" }); |
| 115 | + expect(msg).toBe("Issue created: [#15](https://github.com/owner/repo/issues/15)"); |
| 116 | + }); |
| 117 | + |
| 118 | + it("uses custom template from config", () => { |
| 119 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ issueCreated: "New issue #{item_number}" }); |
| 120 | + const msg = getIssueCreatedMessage({ itemNumber: 3, itemUrl: "https://github.com/owner/repo/issues/3" }); |
| 121 | + expect(msg).toBe("New issue #3"); |
| 122 | + }); |
| 123 | + }); |
| 124 | + |
| 125 | + describe("getCommitPushedMessage", () => { |
| 126 | + const SHA = "abc1234def5678901234567890123456789012ab"; |
| 127 | + const SHORT = "abc1234"; |
| 128 | + const COMMIT_URL = `https://github.com/owner/repo/commit/${SHA}`; |
| 129 | + |
| 130 | + it("returns default template with short_sha and commit_url substituted", () => { |
| 131 | + const msg = getCommitPushedMessage({ commitSha: SHA, shortSha: SHORT, commitUrl: COMMIT_URL }); |
| 132 | + expect(msg).toBe(`Commit pushed: [\`${SHORT}\`](${COMMIT_URL})`); |
| 133 | + }); |
| 134 | + |
| 135 | + it("uses custom template from config", () => { |
| 136 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ commitPushed: "Pushed {short_sha} to repo" }); |
| 137 | + const msg = getCommitPushedMessage({ commitSha: SHA, shortSha: SHORT, commitUrl: COMMIT_URL }); |
| 138 | + expect(msg).toBe(`Pushed ${SHORT} to repo`); |
| 139 | + }); |
| 140 | + |
| 141 | + it("supports full SHA in custom template", () => { |
| 142 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ commitPushed: "{commit_sha}" }); |
| 143 | + const msg = getCommitPushedMessage({ commitSha: SHA, shortSha: SHORT, commitUrl: COMMIT_URL }); |
| 144 | + expect(msg).toBe(SHA); |
| 145 | + }); |
| 146 | + }); |
| 147 | + |
| 148 | + describe("fallback when config is missing keys", () => { |
| 149 | + it("uses default template when only unrelated config keys are set", () => { |
| 150 | + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ footer: "custom footer" }); |
| 151 | + expect(getRunStartedMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, eventType: "issue" })).toContain("has started processing"); |
| 152 | + expect(getRunSuccessMessage({ workflowName: WORKFLOW, runUrl: RUN_URL })).toContain("completed successfully"); |
| 153 | + expect(getRunFailureMessage({ workflowName: WORKFLOW, runUrl: RUN_URL, status: "failed" })).toContain("failed"); |
| 154 | + }); |
| 155 | + }); |
| 156 | +}); |
0 commit comments