@@ -58,7 +58,6 @@ await jest.unstable_mockModule('@actions/github', async () => {
5858 payload : { } ,
5959 repo : { owner : 'test-owner' , repo : 'test-repo' } ,
6060 } ,
61- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6261 } as any ;
6362} ) ;
6463
@@ -83,9 +82,11 @@ let setOutputMock: jest.Mock;
8382let mockOctokit : {
8483 rest : {
8584 issues : {
86- createComment : jest . Mock ;
85+ createComment : jest . Mock < any > ;
86+ listComments : jest . Mock < any > ;
8787 } ;
8888 } ;
89+ graphql : jest . Mock < any > ;
8990} ;
9091
9192describe ( 'action' , ( ) => {
@@ -140,8 +141,10 @@ describe('action', () => {
140141 rest : {
141142 issues : {
142143 createComment : jest . fn ( ) ,
144+ listComments : jest . fn ( ) ,
143145 } ,
144146 } ,
147+ graphql : jest . fn ( ) ,
145148 } ;
146149 githubMocks . getOctokit . mockReturnValue ( mockOctokit ) ;
147150 } ) ;
@@ -406,9 +409,41 @@ at Tests.Registration.main(Registration.java:202)`,
406409 } ;
407410 testInputs . reports = [ 'junit|fixtures/junit-many-errors.xml' ] ;
408411 testInputs [ 'max-annotations' ] = '2' ;
409- // eslint-disable-next-line @typescript-eslint/no-explicit-any
410- ( mockOctokit . rest . issues . createComment as any ) . mockResolvedValue ( { } ) ;
412+ // Mock listComments to return some previous bot comments
413+ mockOctokit . rest . issues . listComments . mockResolvedValue ( {
414+ data : [
415+ {
416+ id : 1 ,
417+ node_id : 'comment1' ,
418+ body : '## Skipped Annotations\n\nOld comment' ,
419+ } ,
420+ {
421+ id : 2 ,
422+ node_id : 'comment2' ,
423+ body : 'Some other comment' ,
424+ } ,
425+ ] ,
426+ } ) ;
427+ // Mock graphql for minimizing comments
428+ mockOctokit . graphql . mockResolvedValue ( { } ) ;
429+ mockOctokit . rest . issues . createComment . mockResolvedValue ( { } ) ;
411430 await main . run ( ) ;
431+ expect ( mockOctokit . rest . issues . listComments ) . toHaveBeenCalledWith ( {
432+ owner : 'test-owner' ,
433+ repo : 'test-repo' ,
434+ issue_number : 123 ,
435+ page : 1 ,
436+ per_page : 100 ,
437+ } ) ;
438+ expect ( mockOctokit . graphql ) . toHaveBeenCalledWith (
439+ expect . stringContaining ( 'MinimizeComment' ) ,
440+ {
441+ input : {
442+ subjectId : 'comment1' ,
443+ classifier : 'OUTDATED' ,
444+ } ,
445+ } ,
446+ ) ;
412447 expect ( mockOctokit . rest . issues . createComment ) . toHaveBeenCalledWith ( {
413448 owner : 'test-owner' ,
414449 repo : 'test-repo' ,
@@ -427,15 +462,109 @@ at Tests.Registration.main(Registration.java:202)`,
427462 } ;
428463 testInputs . reports = [ 'junit|fixtures/junit-many-errors.xml' ] ;
429464 testInputs [ 'max-annotations' ] = '2' ;
465+ // Mock listComments
466+ mockOctokit . rest . issues . listComments . mockResolvedValue ( {
467+ data : [ ] ,
468+ } ) ;
469+ // Mock graphql
470+ mockOctokit . graphql . mockResolvedValue ( { } ) ;
430471 const apiError = new Error ( 'API Error' ) ;
431- // eslint-disable-next-line @typescript-eslint/no-explicit-any
432- ( mockOctokit . rest . issues . createComment as any ) . mockRejectedValue ( apiError ) ;
472+ mockOctokit . rest . issues . createComment . mockRejectedValue ( apiError ) ;
433473 await main . run ( ) ;
434474 expect ( errorMock ) . toHaveBeenCalledWith (
435475 `Failed to create PR comment: ${ apiError } ` ,
436476 ) ;
437477 } ) ;
438478
479+ it ( 'should handle pagination when fetching comments' , async ( ) => {
480+ // Mock GitHub context to be on a PR
481+ ( github . context as MutableContext ) . payload = {
482+ pull_request : { number : 123 } ,
483+ } ;
484+ testInputs . reports = [ 'junit|fixtures/junit-many-errors.xml' ] ;
485+ testInputs [ 'max-annotations' ] = '2' ;
486+ // Mock listComments to return full page on first call, then empty page
487+ mockOctokit . rest . issues . listComments
488+ . mockResolvedValueOnce ( {
489+ data : Array ( 100 )
490+ . fill ( null )
491+ . map ( ( _ , i ) => ( {
492+ id : i + 1 ,
493+ node_id : `comment${ i + 1 } ` ,
494+ body : '## Skipped Annotations\n\nOld comment' ,
495+ } ) ) ,
496+ } )
497+ . mockResolvedValueOnce ( {
498+ data : [ ] ,
499+ } ) ;
500+ // Mock graphql for minimizing comments
501+ mockOctokit . graphql . mockResolvedValue ( { } ) ;
502+ mockOctokit . rest . issues . createComment . mockResolvedValue ( { } ) ;
503+ await main . run ( ) ;
504+ expect ( mockOctokit . rest . issues . listComments ) . toHaveBeenCalledTimes ( 2 ) ;
505+ expect ( mockOctokit . rest . issues . listComments ) . toHaveBeenCalledWith ( {
506+ owner : 'test-owner' ,
507+ repo : 'test-repo' ,
508+ issue_number : 123 ,
509+ page : 1 ,
510+ per_page : 100 ,
511+ } ) ;
512+ expect ( mockOctokit . rest . issues . listComments ) . toHaveBeenCalledWith ( {
513+ owner : 'test-owner' ,
514+ repo : 'test-repo' ,
515+ issue_number : 123 ,
516+ page : 2 ,
517+ per_page : 100 ,
518+ } ) ;
519+ expect ( mockOctokit . graphql ) . toHaveBeenCalledTimes ( 100 ) ;
520+ } ) ;
521+
522+ it ( 'should handle GraphQL minimization failure for individual comments' , async ( ) => {
523+ // Mock GitHub context to be on a PR
524+ ( github . context as MutableContext ) . payload = {
525+ pull_request : { number : 123 } ,
526+ } ;
527+ testInputs . reports = [ 'junit|fixtures/junit-many-errors.xml' ] ;
528+ testInputs [ 'max-annotations' ] = '2' ;
529+ // Mock listComments to return bot comments
530+ mockOctokit . rest . issues . listComments . mockResolvedValue ( {
531+ data : [
532+ {
533+ id : 1 ,
534+ node_id : 'comment1' ,
535+ body : '## Skipped Annotations\n\nOld comment' ,
536+ } ,
537+ ] ,
538+ } ) ;
539+ // Mock graphql to fail for minimization
540+ const graphqlError = new Error ( 'GraphQL Error' ) ;
541+ mockOctokit . graphql . mockRejectedValue ( graphqlError ) ;
542+ mockOctokit . rest . issues . createComment . mockResolvedValue ( { } ) ;
543+ await main . run ( ) ;
544+ expect ( warningMock ) . toHaveBeenCalledWith (
545+ 'Failed to minimize comment 1: Error: GraphQL Error' ,
546+ ) ;
547+ expect ( mockOctokit . rest . issues . createComment ) . toHaveBeenCalled ( ) ;
548+ } ) ;
549+
550+ it ( 'should handle listComments API failure' , async ( ) => {
551+ // Mock GitHub context to be on a PR
552+ ( github . context as MutableContext ) . payload = {
553+ pull_request : { number : 123 } ,
554+ } ;
555+ testInputs . reports = [ 'junit|fixtures/junit-many-errors.xml' ] ;
556+ testInputs [ 'max-annotations' ] = '2' ;
557+ // Mock listComments to fail
558+ const apiError = new Error ( 'API Error' ) ;
559+ mockOctokit . rest . issues . listComments . mockRejectedValue ( apiError ) ;
560+ mockOctokit . rest . issues . createComment . mockResolvedValue ( { } ) ;
561+ await main . run ( ) ;
562+ expect ( warningMock ) . toHaveBeenCalledWith (
563+ 'Failed to minimize previous bot comments: Error: API Error' ,
564+ ) ;
565+ expect ( mockOctokit . rest . issues . createComment ) . toHaveBeenCalled ( ) ;
566+ } ) ;
567+
439568 it ( 'should throw error for invalid report format' , async ( ) => {
440569 testInputs . reports = [ 'invalid-format-no-pipe' ] ;
441570 await expect ( main . run ( ) ) . rejects . toThrow (
0 commit comments