Skip to content

Commit 3bbec31

Browse files
Copilotmarocchino
andauthored
Add comprehensive tests for main.ts covering all branches (#1660)
* Initial plan * test: add comprehensive tests for main.ts covering all branches Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>
1 parent aaf6178 commit 3bbec31

File tree

1 file changed

+265
-0
lines changed

1 file changed

+265
-0
lines changed

__tests__/main.test.ts

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
import {beforeEach, describe, expect, test, vi} from "vitest"
2+
3+
vi.mock("@actions/core", () => ({
4+
info: vi.fn(),
5+
setFailed: vi.fn(),
6+
setOutput: vi.fn(),
7+
}))
8+
9+
vi.mock("@actions/github", () => ({
10+
getOctokit: vi.fn().mockReturnValue({}),
11+
}))
12+
13+
vi.mock("../src/comment", () => ({
14+
commentsEqual: vi.fn(),
15+
createComment: vi.fn(),
16+
deleteComment: vi.fn(),
17+
findPreviousComment: vi.fn(),
18+
getBodyOf: vi.fn(),
19+
minimizeComment: vi.fn(),
20+
updateComment: vi.fn(),
21+
}))
22+
23+
const mockConfig = {
24+
append: false,
25+
deleteOldComment: false,
26+
getBody: vi.fn(),
27+
githubToken: "some-token",
28+
header: "",
29+
hideAndRecreate: false,
30+
hideClassify: "OUTDATED",
31+
hideDetails: false,
32+
hideOldComment: false,
33+
ignoreEmpty: false,
34+
onlyCreateComment: false,
35+
onlyUpdateComment: false,
36+
pullRequestNumber: 123,
37+
recreate: false,
38+
repo: {owner: "marocchino", repo: "sticky-pull-request-comment"},
39+
skipUnchanged: false,
40+
}
41+
42+
vi.mock("../src/config", () => mockConfig)
43+
44+
const flushPromises = () => new Promise<void>(resolve => setTimeout(resolve, 0))
45+
46+
async function runMain(
47+
setup?: (mocks: {comment: typeof import("../src/comment")}) => void,
48+
) {
49+
vi.resetModules()
50+
const comment = await import("../src/comment")
51+
vi.mocked(comment.findPreviousComment).mockResolvedValue(null)
52+
vi.mocked(comment.createComment).mockResolvedValue({data: {id: 456}} as any)
53+
vi.mocked(comment.deleteComment).mockResolvedValue(undefined)
54+
vi.mocked(comment.updateComment).mockResolvedValue(undefined)
55+
vi.mocked(comment.minimizeComment).mockResolvedValue(undefined)
56+
vi.mocked(comment.commentsEqual).mockReturnValue(false)
57+
vi.mocked(comment.getBodyOf).mockReturnValue(undefined)
58+
setup?.({comment})
59+
await import("../src/main")
60+
await flushPromises()
61+
const core = await import("@actions/core")
62+
return {comment, core}
63+
}
64+
65+
beforeEach(() => {
66+
mockConfig.append = false
67+
mockConfig.deleteOldComment = false
68+
mockConfig.getBody = vi.fn().mockResolvedValue("test body")
69+
mockConfig.githubToken = "some-token"
70+
mockConfig.header = ""
71+
mockConfig.hideAndRecreate = false
72+
mockConfig.hideClassify = "OUTDATED"
73+
mockConfig.hideDetails = false
74+
mockConfig.hideOldComment = false
75+
mockConfig.ignoreEmpty = false
76+
mockConfig.onlyCreateComment = false
77+
mockConfig.onlyUpdateComment = false
78+
mockConfig.pullRequestNumber = 123
79+
mockConfig.recreate = false
80+
mockConfig.repo = {owner: "marocchino", repo: "sticky-pull-request-comment"}
81+
mockConfig.skipUnchanged = false
82+
})
83+
84+
describe("run", () => {
85+
test("skips step when pullRequestNumber is NaN", async () => {
86+
mockConfig.pullRequestNumber = NaN
87+
const {comment, core} = await runMain()
88+
expect(core.info).toHaveBeenCalledWith("no pull request numbers given: skip step")
89+
expect(comment.findPreviousComment).not.toHaveBeenCalled()
90+
})
91+
92+
test("skips step when pullRequestNumber is less than 1", async () => {
93+
mockConfig.pullRequestNumber = 0
94+
const {comment, core} = await runMain()
95+
expect(core.info).toHaveBeenCalledWith("no pull request numbers given: skip step")
96+
expect(comment.findPreviousComment).not.toHaveBeenCalled()
97+
})
98+
99+
test("skips step when body is empty and ignoreEmpty is true", async () => {
100+
mockConfig.getBody = vi.fn().mockResolvedValue("")
101+
mockConfig.ignoreEmpty = true
102+
const {comment, core} = await runMain()
103+
expect(core.info).toHaveBeenCalledWith("no body given: skip step by ignoreEmpty")
104+
expect(comment.findPreviousComment).not.toHaveBeenCalled()
105+
})
106+
107+
test("fails when body is empty and no delete or hide flags are set", async () => {
108+
mockConfig.getBody = vi.fn().mockResolvedValue("")
109+
const {core} = await runMain()
110+
expect(core.setFailed).toHaveBeenCalledWith("Either message or path input is required")
111+
})
112+
113+
test("fails when deleteOldComment and recreate are both true", async () => {
114+
mockConfig.deleteOldComment = true
115+
mockConfig.recreate = true
116+
const {core} = await runMain()
117+
expect(core.setFailed).toHaveBeenCalledWith(
118+
"delete and recreate cannot be both set to true",
119+
)
120+
})
121+
122+
test("fails when onlyCreateComment and onlyUpdateComment are both true", async () => {
123+
mockConfig.onlyCreateComment = true
124+
mockConfig.onlyUpdateComment = true
125+
const {core} = await runMain()
126+
expect(core.setFailed).toHaveBeenCalledWith(
127+
"only_create and only_update cannot be both set to true",
128+
)
129+
})
130+
131+
test("fails when hideOldComment and hideAndRecreate are both true", async () => {
132+
mockConfig.hideOldComment = true
133+
mockConfig.hideAndRecreate = true
134+
const {core} = await runMain()
135+
expect(core.setFailed).toHaveBeenCalledWith(
136+
"hide and hide_and_recreate cannot be both set to true",
137+
)
138+
})
139+
140+
test("deletes previous comment when deleteOldComment is true and previous exists", async () => {
141+
mockConfig.deleteOldComment = true
142+
const previous = {id: "existing-id", body: "old body"}
143+
const {comment, core} = await runMain(({comment}) => {
144+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
145+
})
146+
expect(core.setOutput).toHaveBeenCalledWith("previous_comment_id", "existing-id")
147+
expect(comment.deleteComment).toHaveBeenCalledWith(expect.anything(), "existing-id")
148+
expect(comment.createComment).not.toHaveBeenCalled()
149+
})
150+
151+
test("skips delete when deleteOldComment is true but no previous comment exists", async () => {
152+
mockConfig.deleteOldComment = true
153+
const {comment, core} = await runMain()
154+
expect(core.setOutput).toHaveBeenCalledWith("previous_comment_id", undefined)
155+
expect(comment.deleteComment).not.toHaveBeenCalled()
156+
})
157+
158+
test("skips creating comment when onlyUpdateComment is true and no previous exists", async () => {
159+
mockConfig.onlyUpdateComment = true
160+
const {comment} = await runMain()
161+
expect(comment.createComment).not.toHaveBeenCalled()
162+
})
163+
164+
test("creates comment when no previous comment exists", async () => {
165+
const {comment, core} = await runMain()
166+
expect(comment.createComment).toHaveBeenCalledWith(
167+
expect.anything(),
168+
{owner: "marocchino", repo: "sticky-pull-request-comment"},
169+
123,
170+
"test body",
171+
"",
172+
)
173+
expect(core.setOutput).toHaveBeenCalledWith("created_comment_id", 456)
174+
})
175+
176+
test("skips update when onlyCreateComment is true and previous exists", async () => {
177+
mockConfig.onlyCreateComment = true
178+
const previous = {id: "existing-id", body: "old body"}
179+
const {comment} = await runMain(({comment}) => {
180+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
181+
})
182+
expect(comment.updateComment).not.toHaveBeenCalled()
183+
expect(comment.createComment).not.toHaveBeenCalled()
184+
})
185+
186+
test("minimizes previous comment when hideOldComment is true", async () => {
187+
mockConfig.hideOldComment = true
188+
const previous = {id: "existing-id", body: "old body"}
189+
const {comment} = await runMain(({comment}) => {
190+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
191+
})
192+
expect(comment.minimizeComment).toHaveBeenCalledWith(
193+
expect.anything(),
194+
"existing-id",
195+
"OUTDATED",
196+
)
197+
expect(comment.updateComment).not.toHaveBeenCalled()
198+
})
199+
200+
test("skips update when skipUnchanged is true and body is unchanged", async () => {
201+
mockConfig.skipUnchanged = true
202+
const previous = {id: "existing-id", body: "old body"}
203+
const {comment} = await runMain(({comment}) => {
204+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
205+
vi.mocked(comment.commentsEqual).mockReturnValue(true)
206+
})
207+
expect(comment.updateComment).not.toHaveBeenCalled()
208+
expect(comment.createComment).not.toHaveBeenCalled()
209+
})
210+
211+
test("deletes and recreates comment when recreate is true", async () => {
212+
mockConfig.recreate = true
213+
const previous = {id: "existing-id", body: "old body"}
214+
const {comment, core} = await runMain(({comment}) => {
215+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
216+
vi.mocked(comment.getBodyOf).mockReturnValue("previous body content")
217+
})
218+
expect(comment.deleteComment).toHaveBeenCalledWith(expect.anything(), "existing-id")
219+
expect(comment.createComment).toHaveBeenCalledWith(
220+
expect.anything(),
221+
expect.anything(),
222+
expect.anything(),
223+
"test body",
224+
"",
225+
"previous body content",
226+
)
227+
expect(core.setOutput).toHaveBeenCalledWith("created_comment_id", 456)
228+
})
229+
230+
test("minimizes and recreates comment when hideAndRecreate is true", async () => {
231+
mockConfig.hideAndRecreate = true
232+
const previous = {id: "existing-id", body: "old body"}
233+
const {comment, core} = await runMain(({comment}) => {
234+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
235+
})
236+
expect(comment.minimizeComment).toHaveBeenCalledWith(
237+
expect.anything(),
238+
"existing-id",
239+
"OUTDATED",
240+
)
241+
expect(comment.createComment).toHaveBeenCalledWith(
242+
expect.anything(),
243+
expect.anything(),
244+
expect.anything(),
245+
"test body",
246+
"",
247+
)
248+
expect(core.setOutput).toHaveBeenCalledWith("created_comment_id", 456)
249+
})
250+
251+
test("updates existing comment by default", async () => {
252+
const previous = {id: "existing-id", body: "old body"}
253+
const {comment} = await runMain(({comment}) => {
254+
vi.mocked(comment.findPreviousComment).mockResolvedValue(previous as any)
255+
vi.mocked(comment.getBodyOf).mockReturnValue("previous body content")
256+
})
257+
expect(comment.updateComment).toHaveBeenCalledWith(
258+
expect.anything(),
259+
"existing-id",
260+
"test body",
261+
"",
262+
"previous body content",
263+
)
264+
})
265+
})

0 commit comments

Comments
 (0)