Skip to content

Commit 80a4bc2

Browse files
committed
test: ✅ Add test for the action
1 parent 38a4305 commit 80a4bc2

File tree

3 files changed

+223
-147
lines changed

3 files changed

+223
-147
lines changed

__tests__/index.test.ts

Lines changed: 223 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,239 @@
1-
/**
2-
* Unit tests for the action's entrypoint, src/index.ts
3-
*/
4-
5-
import { context } from '@actions/github';
6-
import * as main from '../src/main';
1+
import { run } from '../src/index';
2+
import * as core from '@actions/core';
3+
import * as github from '@actions/github';
4+
import { readFile } from 'fs/promises'; //eslint-disable-line @typescript-eslint/no-unused-vars
75

6+
jest.mock('@actions/core');
87
jest.mock('@actions/github');
8+
jest.mock('fs/promises');
9+
10+
describe('Create Release', () => {
11+
const getInput = core.getInput as jest.Mock;
12+
const getOctokit = github.getOctokit as jest.Mock;
913

10-
const mockedContext = context as jest.Mock<typeof context>;
14+
let originalEnv: NodeJS.ProcessEnv; //eslint-disable-line no-undef
15+
const owner = 'owner';
16+
const repo = 'repo';
1117

12-
// Mock the action's entrypoint
13-
const runMock = jest.spyOn(main, 'run').mockImplementation();
18+
(github.context as object) = { repo: { owner, repo }, sha: 'sha' };
1419

15-
describe('Create Release', () => {
16-
let createRelease;
17-
18-
beforeEach(() => {
19-
createRelease = jest.fn().mockReturnValueOnce({
20-
data: {
21-
id: 'releaseId',
22-
html_url: 'htmlUrl',
23-
upload_url: 'uploadUrl'
24-
}
20+
const mockCreateReleaseResponse = {
21+
data: {
22+
id: 123,
23+
html_url: `https://github.com/${owner}/${repo}/releases/tag/v1.0.0`,
24+
upload_url: 'https://github.com/upload'
25+
}
26+
};
27+
28+
const mockOctokit = {
29+
request: jest.fn().mockResolvedValueOnce(mockCreateReleaseResponse)
30+
};
31+
32+
beforeAll(() => {
33+
originalEnv = process.env;
34+
process.env = { ...originalEnv, GITHUB_TOKEN: 'fakeToken' };
35+
});
36+
37+
afterAll(() => {
38+
process.env = originalEnv;
39+
});
40+
41+
afterEach(() => {
42+
jest.clearAllMocks();
43+
});
44+
45+
it('Should set outputs', async () => {
46+
getInput
47+
.mockReturnValueOnce('refs/tags/v1.0.0')
48+
.mockReturnValueOnce('myRelease')
49+
.mockReturnValueOnce('myBody')
50+
.mockReturnValueOnce('false')
51+
.mockReturnValueOnce('false');
52+
53+
getOctokit.mockReturnValueOnce(mockOctokit);
54+
55+
(core.setOutput as jest.Mock) = jest.fn();
56+
57+
await run();
58+
59+
expect(core.setOutput).toHaveBeenNthCalledWith(1, 'id', 123);
60+
expect(core.setOutput).toHaveBeenNthCalledWith(2, 'html_url', `https://github.com/owner/repo/releases/tag/v1.0.0`);
61+
expect(core.setOutput).toHaveBeenNthCalledWith(3, 'upload_url', 'https://github.com/upload');
62+
});
63+
64+
it('Should create a release', async () => {
65+
getInput
66+
.mockReturnValueOnce('refs/tags/v1.0.0')
67+
.mockReturnValueOnce('myRelease')
68+
.mockReturnValueOnce('myBody')
69+
.mockReturnValueOnce('false')
70+
.mockReturnValueOnce('false');
71+
72+
const mockOctokit = {
73+
request: jest.fn().mockResolvedValueOnce(mockCreateReleaseResponse)
74+
};
75+
getOctokit.mockReturnValueOnce(mockOctokit);
76+
77+
await run();
78+
79+
expect(mockOctokit.request).toHaveBeenCalledWith('POST /repos/owner/repo/releases', {
80+
owner: 'owner',
81+
repo: 'repo',
82+
tag_name: 'v1.0.0',
83+
name: 'myRelease',
84+
body: 'myBody',
85+
draft: false,
86+
prerelease: false,
87+
target_commitish: 'sha'
2588
});
89+
});
90+
91+
it('Should create a draft release', async () => {
92+
getInput
93+
.mockReturnValueOnce('refs/tags/v1.0.0')
94+
.mockReturnValueOnce('myRelease')
95+
.mockReturnValueOnce('myBody')
96+
.mockReturnValueOnce('true')
97+
.mockReturnValueOnce('false');
98+
99+
getOctokit.mockReturnValueOnce(mockOctokit);
100+
101+
await run();
26102

27-
mockedContext.mock.repo = {
103+
expect(mockOctokit.request).toHaveBeenCalledWith('POST /repos/owner/repo/releases', {
28104
owner: 'owner',
29-
repo: 'repo'
30-
};
31-
s;
32-
context.sha = 'sha';
105+
repo: 'repo',
106+
tag_name: 'v1.0.0',
107+
name: 'myRelease',
108+
body: 'myBody',
109+
draft: true,
110+
prerelease: false,
111+
target_commitish: 'sha'
112+
});
113+
});
33114

34-
const github = {
35-
repos: {
36-
createRelease
37-
}
115+
it('Should create a pre-release', async () => {
116+
getInput
117+
.mockReturnValueOnce('refs/tags/v1.0.0')
118+
.mockReturnValueOnce('myRelease')
119+
.mockReturnValueOnce('myBody')
120+
.mockReturnValueOnce('false')
121+
.mockReturnValueOnce('true');
122+
123+
getOctokit.mockReturnValueOnce(mockOctokit);
124+
125+
await run();
126+
127+
expect(mockOctokit.request).toHaveBeenCalledWith('POST /repos/owner/repo/releases', {
128+
owner: 'owner',
129+
repo: 'repo',
130+
tag_name: 'v1.0.0',
131+
name: 'myRelease',
132+
body: 'myBody',
133+
draft: false,
134+
prerelease: true,
135+
target_commitish: 'sha'
136+
});
137+
});
138+
139+
it('Should create an empty body release', async () => {
140+
getInput
141+
.mockReturnValueOnce('refs/tags/v1.0.0')
142+
.mockReturnValueOnce('myRelease')
143+
.mockReturnValueOnce('') // <-- The default value for body in action.yml
144+
.mockReturnValueOnce('false')
145+
.mockReturnValueOnce('false');
146+
147+
getOctokit.mockReturnValueOnce(mockOctokit);
148+
149+
await run();
150+
151+
expect(mockOctokit.request).toHaveBeenCalledWith('POST /repos/owner/repo/releases', {
152+
owner: 'owner',
153+
repo: 'repo',
154+
tag_name: 'v1.0.0',
155+
name: 'myRelease',
156+
body: '',
157+
draft: false,
158+
prerelease: false,
159+
target_commitish: 'sha'
160+
});
161+
});
162+
163+
it('Should create a release with a body based on a file', async () => {
164+
getInput
165+
.mockReturnValueOnce('refs/tags/v1.0.0')
166+
.mockReturnValueOnce('myRelease')
167+
.mockReturnValueOnce('') // <-- The default value for body in action.yml
168+
.mockReturnValueOnce('false')
169+
.mockReturnValueOnce('false')
170+
.mockReturnValueOnce(null)
171+
.mockReturnValueOnce('notes.md');
172+
173+
(readFile as jest.Mock) = jest
174+
.fn()
175+
.mockResolvedValueOnce('# this is a release\nThe markdown is strong in this one.');
176+
177+
getOctokit.mockReturnValueOnce(mockOctokit);
178+
179+
await run();
180+
181+
expect(mockOctokit.request).toHaveBeenCalledWith('POST /repos/owner/repo/releases', {
182+
owner: 'owner',
183+
repo: 'repo',
184+
tag_name: 'v1.0.0',
185+
name: 'myRelease',
186+
body: '# this is a release\nThe markdown is strong in this one.',
187+
draft: false,
188+
prerelease: false,
189+
target_commitish: 'sha'
190+
});
191+
});
192+
193+
it('Should fail elegantly if octokit throws an exception', async () => {
194+
getInput
195+
.mockReturnValueOnce('refs/tags/v1.0.0')
196+
.mockReturnValueOnce('myRelease')
197+
.mockReturnValueOnce('myBody')
198+
.mockReturnValueOnce('false')
199+
.mockReturnValueOnce('false');
200+
201+
const mockOctokit = {
202+
request: jest.fn().mockImplementation(() => {
203+
throw new Error('Error creating release');
204+
})
38205
};
206+
getOctokit.mockReturnValueOnce(mockOctokit);
207+
208+
(core.setOutput as jest.Mock) = jest.fn();
209+
(core.setFailed as jest.Mock) = jest.fn();
39210

40-
GitHub.mockImplementation(() => github);
211+
await run();
212+
213+
expect(mockOctokit.request).toHaveBeenCalled();
214+
expect(core.setFailed).toHaveBeenCalledWith('Error creating release');
215+
expect(core.setOutput).toHaveBeenCalledTimes(0);
41216
});
42217

43-
it('calls run when imported', async () => {
44-
// eslint-disable-next-line @typescript-eslint/no-require-imports
45-
require('../src/index');
218+
it('Should fail elegantly if cannot read body file', async () => {
219+
getInput
220+
.mockReturnValueOnce('refs/tags/v1.0.0')
221+
.mockReturnValueOnce('myRelease')
222+
.mockReturnValueOnce('') // <-- The default value for body in action.yml
223+
.mockReturnValueOnce('false')
224+
.mockReturnValueOnce('false')
225+
.mockReturnValueOnce(null)
226+
.mockReturnValueOnce('notes.md');
227+
228+
(readFile as jest.Mock) = jest.fn().mockImplementation(() => {
229+
throw new Error('Error');
230+
});
231+
232+
getOctokit.mockReturnValueOnce(mockOctokit);
233+
(core.setFailed as jest.Mock) = jest.fn();
234+
235+
await run();
46236

47-
expect(runMock).toHaveBeenCalled();
237+
expect(core.setFailed).toHaveBeenCalledWith('Error');
48238
});
49239
});

__tests__/main.test.ts

Lines changed: 0 additions & 89 deletions
This file was deleted.

__tests__/wait.test.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)