@@ -236,7 +236,7 @@ describe("runPost", () => {
236236 ) ;
237237 } ) ;
238238
239- it ( "should re-throw errors during HTTP client post operation " , async ( ) => {
239+ it ( "should re-throw errors after all retry attempts fail " , async ( ) => {
240240 // Mock successful workflow for status checking
241241 const workflowRun = createMockWorkflowRun ( "in_progress" , null ) ;
242242 const jobs = {
@@ -258,10 +258,56 @@ describe("runPost", () => {
258258 if ( name === STATE_FLY_ACCESS_TOKEN ) return "test-access-token" ;
259259 return "" ;
260260 } ) ;
261+ // Mock all retries failing
261262 mockHttpClientPost . mockRejectedValue ( new Error ( "Network error" ) ) ;
262263
263264 await expect ( runPost ( ) ) . rejects . toThrow ( "Network error" ) ;
264- } ) ;
265+ // Should have tried 3 times (MAX_RETRIES)
266+ expect ( mockHttpClientPost ) . toHaveBeenCalledTimes ( 3 ) ;
267+ } , 15000 ) ; // Increase timeout for retry delays
268+
269+ it ( "should succeed on retry after initial failure" , async ( ) => {
270+ // Mock successful workflow for status checking
271+ const workflowRun = createMockWorkflowRun ( "in_progress" , null ) ;
272+ const jobs = {
273+ jobs : [
274+ createMockJob ( "test-job" , "in_progress" , null , [
275+ createMockStep ( "Checkout" , "success" ) ,
276+ ] ) ,
277+ ] ,
278+ } ;
279+
280+ const mockOctokit = createMockOctokit ( workflowRun , jobs ) ;
281+ mockGithub . getOctokit . mockReturnValue (
282+ mockOctokit as unknown as ReturnType < typeof mockGithub . getOctokit > ,
283+ ) ;
284+
285+ mockCore . getState . mockImplementation ( ( name : string ) => {
286+ if ( name === STATE_FLY_URL ) return "https://fly.example.com" ;
287+ if ( name === STATE_FLY_ACCESS_TOKEN ) return "test-access-token" ;
288+ if ( name === STATE_FLY_PACKAGE_MANAGERS ) return JSON . stringify ( [ "npm" ] ) ;
289+ return "" ;
290+ } ) ;
291+
292+ // First call fails, second succeeds
293+ const fakeResponse : HttpClientResponse = {
294+ message : { statusCode : 200 , headers : { } as IncomingHttpHeaders } ,
295+ readBody : async ( ) => "Notification sent" ,
296+ } as unknown as HttpClientResponse ;
297+ mockHttpClientPost
298+ . mockRejectedValueOnce ( new Error ( "Timeout" ) )
299+ . mockResolvedValueOnce ( fakeResponse ) ;
300+
301+ await runPost ( ) ;
302+
303+ expect ( mockHttpClientPost ) . toHaveBeenCalledTimes ( 2 ) ;
304+ expect ( mockCore . warning ) . toHaveBeenCalledWith (
305+ expect . stringContaining ( "Request failed (attempt 1/3)" ) ,
306+ ) ;
307+ expect ( mockCore . info ) . toHaveBeenCalledWith (
308+ "✅ CI end notification completed successfully" ,
309+ ) ;
310+ } , 15000 ) ;
265311
266312 it ( "should re-throw error if HTTP response is not 200" , async ( ) => {
267313 // Mock successful workflow for status checking
@@ -389,11 +435,45 @@ describe("runPost", () => {
389435 expect ( mockCore . warning ) . toHaveBeenCalledWith (
390436 "Failed to check job status via GitHub API: Error: API Error" ,
391437 ) ;
392- expect ( mockHttpClientPost ) . toHaveBeenCalledWith (
393- expect . any ( String ) ,
394- JSON . stringify ( { status : "success" , package_managers : [ "npm" , "maven" ] } ) ,
395- expect . any ( Object ) ,
438+ expect ( mockHttpClientPost ) . toHaveBeenCalled ( ) ;
439+ } ) ;
440+
441+ it ( "should handle GitHub API permission error gracefully without warning" , async ( ) => {
442+ // Mock GitHub API permission error (expected when actions:read is not granted)
443+ const mockOctokit = {
444+ rest : {
445+ actions : {
446+ listJobsForWorkflowRun : jest
447+ . fn ( )
448+ . mockRejectedValue (
449+ new Error (
450+ "Resource not accessible by integration - https://docs.github.com/rest/actions/workflow-jobs" ,
451+ ) ,
452+ ) ,
453+ } ,
454+ } ,
455+ } ;
456+ mockGithub . getOctokit . mockReturnValue (
457+ mockOctokit as unknown as ReturnType < typeof mockGithub . getOctokit > ,
396458 ) ;
459+
460+ const fakeResponse : HttpClientResponse = {
461+ message : { statusCode : 200 , headers : { } as IncomingHttpHeaders } ,
462+ readBody : async ( ) => "Notification sent" ,
463+ } as unknown as HttpClientResponse ;
464+ mockHttpClientPost . mockResolvedValue ( fakeResponse ) ;
465+
466+ await runPost ( ) ;
467+
468+ // Should use info instead of warning for permission errors
469+ expect ( mockCore . info ) . toHaveBeenCalledWith (
470+ expect . stringContaining ( "Cannot access workflow job status" ) ,
471+ ) ;
472+ // Should NOT emit warning for permission errors
473+ expect ( mockCore . warning ) . not . toHaveBeenCalledWith (
474+ expect . stringContaining ( "Failed to check job status via GitHub API" ) ,
475+ ) ;
476+ expect ( mockHttpClientPost ) . toHaveBeenCalled ( ) ;
397477 } ) ;
398478
399479 it ( "should exclude post action steps from failure detection" , async ( ) => {
@@ -793,7 +873,7 @@ describe("runPostScriptLogic", () => {
793873 expect ( core . setFailed ) . not . toHaveBeenCalled ( ) ;
794874 } ) ;
795875
796- it ( "should call runPost and setFailed on error" , async ( ) => {
876+ it ( "should call runPost and setFailed on error after all retries " , async ( ) => {
797877 // Mock successful workflow setup but HTTP error
798878 const workflowRun = createMockWorkflowRun ( "in_progress" , null ) ;
799879 const jobs = {
@@ -810,15 +890,17 @@ describe("runPostScriptLogic", () => {
810890 ) ;
811891
812892 const errorMessage = "Test error from runPost" ;
813- mockHttpClientPost . mockRejectedValueOnce ( new Error ( errorMessage ) ) ;
893+ // Reject all retry attempts
894+ mockHttpClientPost . mockRejectedValue ( new Error ( errorMessage ) ) ;
814895
815896 await runPostScriptLogic ( ) ;
816897
817- expect ( mockHttpClientPost ) . toHaveBeenCalledTimes ( 1 ) ;
898+ // Should have tried 3 times (MAX_RETRIES)
899+ expect ( mockHttpClientPost ) . toHaveBeenCalledTimes ( 3 ) ;
818900 expect ( core . setFailed ) . toHaveBeenCalledWith ( errorMessage ) ;
819- } ) ;
901+ } , 15000 ) ;
820902
821- it ( "should handle non-Error objects thrown by runPost" , async ( ) => {
903+ it ( "should handle non-Error objects thrown by runPost after all retries " , async ( ) => {
822904 // Mock successful workflow setup but string error
823905 const workflowRun = createMockWorkflowRun ( "in_progress" , null ) ;
824906 const jobs = {
@@ -835,11 +917,13 @@ describe("runPostScriptLogic", () => {
835917 ) ;
836918
837919 const errorString = "Just a string error" ;
838- mockHttpClientPost . mockRejectedValueOnce ( errorString ) ;
920+ // Reject all retry attempts
921+ mockHttpClientPost . mockRejectedValue ( errorString ) ;
839922
840923 await runPostScriptLogic ( ) ;
841924
842- expect ( mockHttpClientPost ) . toHaveBeenCalledTimes ( 1 ) ;
925+ // Should have tried 3 times (MAX_RETRIES)
926+ expect ( mockHttpClientPost ) . toHaveBeenCalledTimes ( 3 ) ;
843927 expect ( core . setFailed ) . toHaveBeenCalledWith ( errorString ) ;
844- } ) ;
928+ } , 15000 ) ;
845929} ) ;
0 commit comments