1
1
const { expect } = require ( 'chai' ) ;
2
2
const sinon = require ( 'sinon' ) ;
3
+ const axios = require ( 'axios' ) ;
3
4
const core = require ( '@actions/core' ) ;
4
5
const ActionInput = require ( '../../src/actionInput' ) ;
5
6
const InputValidator = require ( '../../src/actionInput/inputValidator' ) ;
@@ -19,29 +20,29 @@ describe('Action Input operations for fetching all inputs, triggering validation
19
20
sinon . stub ( InputValidator , 'updateUsername' ) . returns ( 'validatedUsername' ) ;
20
21
sinon . stub ( InputValidator , 'validateBuildName' ) . returns ( 'validatedBuildName' ) ;
21
22
sinon . stub ( InputValidator , 'validateProjectName' ) . returns ( 'validatedProjectName' ) ;
23
+ sinon . stub ( InputValidator , 'validateGithubToken' ) . returns ( 'validatedToken' ) ;
24
+ sinon . stub ( InputValidator , 'validateGithubAppName' ) . returns ( 'validatedAppName' ) ;
25
+
26
+ // Provide required inputs
27
+ stubbedInput . withArgs ( INPUT . USERNAME , { required : true } ) . returns ( 'someUsername' ) ;
28
+ stubbedInput . withArgs ( INPUT . ACCESS_KEY , { required : true } ) . returns ( 'someAccessKey' ) ;
29
+
22
30
process . env . GITHUB_REPOSITORY = 'browserstack/github-actions' ;
31
+ process . env . GITHUB_RUN_ID = '12345' ;
32
+ process . env . GITHUB_RUN_ATTEMPT = '2' ;
23
33
} ) ;
24
34
25
35
afterEach ( ( ) => {
26
- core . getInput . restore ( ) ;
27
- InputValidator . updateUsername . restore ( ) ;
28
- InputValidator . validateBuildName . restore ( ) ;
29
- InputValidator . validateProjectName . restore ( ) ;
36
+ sinon . restore ( ) ;
37
+ delete process . env . GITHUB_REPOSITORY ;
38
+ delete process . env . GITHUB_RUN_ID ;
39
+ delete process . env . GITHUB_RUN_ATTEMPT ;
30
40
} ) ;
31
41
32
42
it ( 'Takes input and validates it successfully' , ( ) => {
33
- stubbedInput . withArgs ( INPUT . USERNAME , { required : true } ) . returns ( 'someUsername' ) ;
34
- stubbedInput . withArgs ( INPUT . ACCESS_KEY , { required : true } ) . returns ( 'someAccessKey' ) ;
35
43
stubbedInput . withArgs ( INPUT . BUILD_NAME ) . returns ( 'someBuildName' ) ;
36
44
stubbedInput . withArgs ( INPUT . PROJECT_NAME ) . returns ( 'someProjectName' ) ;
37
45
const actionInput = new ActionInput ( ) ;
38
- sinon . assert . calledWith ( core . getInput , INPUT . USERNAME , { required : true } ) ;
39
- sinon . assert . calledWith ( core . getInput , INPUT . ACCESS_KEY , { required : true } ) ;
40
- sinon . assert . calledWith ( core . getInput , INPUT . BUILD_NAME ) ;
41
- sinon . assert . calledWith ( core . getInput , INPUT . PROJECT_NAME ) ;
42
- sinon . assert . calledWith ( InputValidator . updateUsername , 'someUsername' ) ;
43
- sinon . assert . calledWith ( InputValidator . validateBuildName , 'someBuildName' ) ;
44
- sinon . assert . calledWith ( InputValidator . validateProjectName , 'someProjectName' ) ;
45
46
expect ( actionInput . username ) . to . eq ( 'validatedUsername' ) ;
46
47
expect ( actionInput . buildName ) . to . eq ( 'validatedBuildName' ) ;
47
48
expect ( actionInput . projectName ) . to . eq ( 'validatedProjectName' ) ;
@@ -55,22 +56,24 @@ describe('Action Input operations for fetching all inputs, triggering validation
55
56
} catch ( e ) {
56
57
expect ( e . message ) . to . eq ( 'Action input failed for reason: Username Required' ) ;
57
58
}
58
- sinon . assert . notCalled ( InputValidator . updateUsername ) ;
59
- sinon . assert . notCalled ( InputValidator . validateBuildName ) ;
60
- sinon . assert . notCalled ( InputValidator . validateProjectName ) ;
61
59
} ) ;
62
60
63
- it ( 'Takes input and throws error if accesskey is not provided in input' , ( ) => {
61
+ it ( 'Takes input and throws error if access key is not provided in input' , ( ) => {
64
62
stubbedInput . withArgs ( INPUT . ACCESS_KEY , { required : true } ) . throws ( Error ( 'Access Key Required' ) ) ;
65
63
try {
66
64
// eslint-disable-next-line no-new
67
65
new ActionInput ( ) ;
68
66
} catch ( e ) {
69
67
expect ( e . message ) . to . eq ( 'Action input failed for reason: Access Key Required' ) ;
70
68
}
71
- sinon . assert . notCalled ( InputValidator . updateUsername ) ;
72
- sinon . assert . notCalled ( InputValidator . validateBuildName ) ;
73
- sinon . assert . notCalled ( InputValidator . validateProjectName ) ;
69
+ } ) ;
70
+
71
+ it ( 'Takes input and validates GitHub token and app name successfully' , ( ) => {
72
+ stubbedInput . withArgs ( INPUT . GITHUB_TOKEN ) . returns ( 'someToken' ) ;
73
+ stubbedInput . withArgs ( INPUT . GITHUB_APP ) . returns ( 'someApp' ) ;
74
+ const actionInput = new ActionInput ( ) ;
75
+ expect ( actionInput . githubToken ) . to . eq ( 'validatedToken' ) ;
76
+ expect ( actionInput . githubApp ) . to . eq ( 'validatedAppName' ) ;
74
77
} ) ;
75
78
} ) ;
76
79
@@ -85,15 +88,10 @@ describe('Action Input operations for fetching all inputs, triggering validation
85
88
} ) ;
86
89
87
90
afterEach ( ( ) => {
88
- core . exportVariable . restore ( ) ;
89
- core . info . restore ( ) ;
90
- core . startGroup . restore ( ) ;
91
- core . endGroup . restore ( ) ;
92
- ActionInput . prototype . _fetchAllInput . restore ( ) ;
93
- ActionInput . prototype . _validateInput . restore ( ) ;
91
+ sinon . restore ( ) ;
94
92
} ) ;
95
93
96
- it ( 'Sets the environment variables required to in test scripts for BrowserStack' , ( ) => {
94
+ it ( 'Sets the environment variables required in test scripts for BrowserStack' , ( ) => {
97
95
const actionInput = new ActionInput ( ) ;
98
96
actionInput . username = 'someUsername' ;
99
97
actionInput . accessKey = 'someAccessKey' ;
@@ -106,4 +104,168 @@ describe('Action Input operations for fetching all inputs, triggering validation
106
104
sinon . assert . calledWith ( core . exportVariable , ENV_VARS . BROWSERSTACK_BUILD_NAME , 'someBuildName' ) ;
107
105
} ) ;
108
106
} ) ;
107
+
108
+ context ( 'Check if BrowserStack Rerun' , ( ) => {
109
+ let stubbedInput ;
110
+
111
+ beforeEach ( ( ) => {
112
+ stubbedInput = sinon . stub ( core , 'getInput' ) ;
113
+ sinon . stub ( InputValidator , 'updateUsername' ) . returns ( 'validatedUsername' ) ;
114
+ sinon . stub ( InputValidator , 'validateBuildName' ) . returns ( 'validatedBuildName' ) ;
115
+ sinon . stub ( InputValidator , 'validateProjectName' ) . returns ( 'validatedProjectName' ) ;
116
+ sinon . stub ( InputValidator , 'validateGithubToken' ) . returns ( 'validatedToken' ) ;
117
+ sinon . stub ( InputValidator , 'validateGithubAppName' ) . returns ( 'validatedAppName' ) ;
118
+
119
+ // Provide required inputs
120
+ stubbedInput . withArgs ( INPUT . USERNAME , { required : true } ) . returns ( 'someUsername' ) ;
121
+ stubbedInput . withArgs ( INPUT . ACCESS_KEY , { required : true } ) . returns ( 'someAccessKey' ) ;
122
+
123
+ process . env . GITHUB_REPOSITORY = 'browserstack/github-actions' ;
124
+ process . env . GITHUB_RUN_ID = '12345' ;
125
+ process . env . GITHUB_RUN_ATTEMPT = '2' ;
126
+ } ) ;
127
+
128
+ afterEach ( ( ) => {
129
+ sinon . restore ( ) ;
130
+ } ) ;
131
+
132
+ it ( 'Returns false if rerun attempt is less than or equal to 1' , async ( ) => {
133
+ // stubbedInput.withArgs(INPUT.GITHUB_APP).returns('someApp');
134
+ const actionInput = new ActionInput ( ) ;
135
+ actionInput . rerunAttempt = '1' ;
136
+ const result = await actionInput . checkIfBStackReRun ( ) ;
137
+ // eslint-disable-next-line no-unused-expressions
138
+ expect ( result ) . to . be . false ;
139
+ } ) ;
140
+
141
+ it ( 'Returns false if runId, repository, or token are invalid' , async ( ) => {
142
+ const actionInput = new ActionInput ( ) ;
143
+ actionInput . runId = '' ;
144
+ const result = await actionInput . checkIfBStackReRun ( ) ;
145
+ // eslint-disable-next-line no-unused-expressions
146
+ expect ( result ) . to . be . false ;
147
+ } ) ;
148
+
149
+ it ( 'Returns true if rerun was triggered by the GitHub App' , async ( ) => {
150
+ const actionInput = new ActionInput ( ) ;
151
+ sinon . stub ( actionInput , 'identifyRunFromBStack' ) . returns ( Promise . resolve ( 'validatedAppName' ) ) ;
152
+ const result = await actionInput . checkIfBStackReRun ( ) ;
153
+ // eslint-disable-next-line no-unused-expressions
154
+ expect ( result ) . to . be . true ;
155
+ } ) ;
156
+
157
+ it ( 'Returns false if rerun was not triggered by the GitHub App' , async ( ) => {
158
+ const actionInput = new ActionInput ( ) ;
159
+ sinon . stub ( actionInput , 'identifyRunFromBStack' ) . returns ( Promise . resolve ( 'otherActor' ) ) ;
160
+ const result = await actionInput . checkIfBStackReRun ( ) ;
161
+ // eslint-disable-next-line no-unused-expressions
162
+ expect ( result ) . to . be . false ;
163
+ } ) ;
164
+ } ) ;
165
+
166
+ context ( 'Identify Run From BrowserStack' , ( ) => {
167
+ let axiosGetStub ;
168
+ let stubbedInput ;
169
+
170
+ beforeEach ( ( ) => {
171
+ stubbedInput = sinon . stub ( core , 'getInput' ) ;
172
+ sinon . stub ( InputValidator , 'updateUsername' ) . returns ( 'validatedUsername' ) ;
173
+ sinon . stub ( InputValidator , 'validateBuildName' ) . returns ( 'validatedBuildName' ) ;
174
+ sinon . stub ( InputValidator , 'validateProjectName' ) . returns ( 'validatedProjectName' ) ;
175
+ sinon . stub ( InputValidator , 'validateGithubToken' ) . returns ( 'validatedToken' ) ;
176
+ sinon . stub ( InputValidator , 'validateGithubAppName' ) . returns ( 'validatedAppName' ) ;
177
+
178
+ // Provide required inputs
179
+ stubbedInput . withArgs ( INPUT . USERNAME , { required : true } ) . returns ( 'someUsername' ) ;
180
+ stubbedInput . withArgs ( INPUT . ACCESS_KEY , { required : true } ) . returns ( 'someAccessKey' ) ;
181
+
182
+ process . env . GITHUB_REPOSITORY = 'browserstack/github-actions' ;
183
+ process . env . GITHUB_RUN_ID = '12345' ;
184
+ process . env . GITHUB_RUN_ATTEMPT = '2' ;
185
+
186
+ // Stub the axios.get method
187
+ axiosGetStub = sinon . stub ( axios , 'get' ) ;
188
+ // Stub core.info to prevent it from throwing an error
189
+ sinon . stub ( core , 'info' ) ;
190
+ } ) ;
191
+
192
+ afterEach ( ( ) => {
193
+ sinon . restore ( ) ;
194
+ } ) ;
195
+
196
+ it ( 'Returns the triggering actor from the GitHub API' , async ( ) => {
197
+ const actionInput = new ActionInput ( ) ;
198
+ axiosGetStub . resolves ( {
199
+ data : {
200
+ triggering_actor : { login : 'someActor' } ,
201
+ } ,
202
+ } ) ;
203
+ const result = await actionInput . identifyRunFromBStack ( ) ;
204
+ expect ( result ) . to . eq ( 'someActor' ) ;
205
+ } ) ;
206
+
207
+ it ( 'Handles errors and returns undefined when GitHub API fails' , async ( ) => {
208
+ const actionInput = new ActionInput ( ) ;
209
+ axiosGetStub . rejects ( new Error ( 'API failed' ) ) ;
210
+ const result = await actionInput . identifyRunFromBStack ( ) ;
211
+ // eslint-disable-next-line no-unused-expressions
212
+ expect ( result ) . to . be . undefined ;
213
+ sinon . assert . calledOnce ( core . info ) ;
214
+ } ) ;
215
+ } ) ;
216
+
217
+ context ( 'Set BrowserStack Rerun Environment Variables' , ( ) => {
218
+ let axiosGetStub ;
219
+ let stubbedInput ;
220
+
221
+ beforeEach ( ( ) => {
222
+ stubbedInput = sinon . stub ( core , 'getInput' ) ;
223
+ sinon . stub ( InputValidator , 'updateUsername' ) . returns ( 'validatedUsername' ) ;
224
+ sinon . stub ( InputValidator , 'validateBuildName' ) . returns ( 'validatedBuildName' ) ;
225
+ sinon . stub ( InputValidator , 'validateProjectName' ) . returns ( 'validatedProjectName' ) ;
226
+ sinon . stub ( InputValidator , 'validateGithubToken' ) . returns ( 'validatedToken' ) ;
227
+ sinon . stub ( InputValidator , 'validateGithubAppName' ) . returns ( 'validatedAppName' ) ;
228
+
229
+ // Provide required inputs
230
+ stubbedInput . withArgs ( INPUT . USERNAME , { required : true } ) . returns ( 'someUsername' ) ;
231
+ stubbedInput . withArgs ( INPUT . ACCESS_KEY , { required : true } ) . returns ( 'someAccessKey' ) ;
232
+
233
+ process . env . GITHUB_REPOSITORY = 'browserstack/github-actions' ;
234
+ process . env . GITHUB_RUN_ID = '12345' ;
235
+ process . env . GITHUB_RUN_ATTEMPT = '2' ;
236
+
237
+ // Stub the axios.get method
238
+ axiosGetStub = sinon . stub ( axios , 'get' ) ;
239
+ // Stub core.info to prevent it from throwing an error
240
+ sinon . stub ( core , 'exportVariable' ) ;
241
+ sinon . stub ( core , 'info' ) ;
242
+ } ) ;
243
+
244
+ afterEach ( ( ) => {
245
+ sinon . restore ( ) ;
246
+ } ) ;
247
+
248
+ it ( 'Sets environment variables from BrowserStack API response' , async ( ) => {
249
+ const actionInput = new ActionInput ( ) ;
250
+ const variables = { VAR1 : 'value1' , VAR2 : 'value2' } ;
251
+ axiosGetStub . resolves ( {
252
+ data : { data : { variables } } ,
253
+ } ) ;
254
+
255
+ await actionInput . setBStackRerunEnvVars ( ) ;
256
+
257
+ sinon . assert . calledWith ( core . exportVariable , 'VAR1' , 'value1' ) ;
258
+ sinon . assert . calledWith ( core . exportVariable , 'VAR2' , 'value2' ) ;
259
+ } ) ;
260
+
261
+ it ( 'Handles errors when BrowserStack API fails' , async ( ) => {
262
+ const actionInput = new ActionInput ( ) ;
263
+ axiosGetStub . rejects ( new Error ( 'API failed' ) ) ;
264
+
265
+ await actionInput . setBStackRerunEnvVars ( ) ;
266
+
267
+ sinon . assert . calledTwice ( core . info ) ;
268
+ sinon . assert . neverCalledWith ( core . exportVariable , sinon . match . any , sinon . match . any ) ;
269
+ } ) ;
270
+ } ) ;
109
271
} ) ;
0 commit comments