11import { Octokit } from '@octokit/rest' ;
22import * as core from '@actions/core' ;
3- import { context } from '@actions/github' ;
4- import { GoogleGenAI } from '@google/genai' ;
5- import { IssueLabeling } from './issue-labeling.js' ;
3+ import { IssueLabeling as _IssueLabeling } from './issue-labeling.js' ;
64
7- class TestableIssueLabeling extends IssueLabeling {
8- public constructor ( git : Octokit , coreService : typeof core ) {
9- super ( git , coreService ) ;
5+ class IssueLabeling extends _IssueLabeling {
6+ setGit ( git : any ) {
7+ this . git = git ;
108 }
119}
1210
1311describe ( 'IssueLabeling' , ( ) => {
14- let mockGit : {
15- paginate : jasmine . Spy ;
16- issues : {
17- listLabelsForRepo : jasmine . Spy ;
18- addLabels : jasmine . Spy ;
19- get : jasmine . Spy ;
20- } ;
21- } ;
12+ let mockGit : jasmine . SpyObj < Octokit > ;
2213 let mockAI : any ;
23- let mockCore : jasmine . SpyObj < typeof core > ;
2414 let issueLabeling : IssueLabeling ;
15+ let getIssue : jasmine . Spy ;
2516
2617 beforeEach ( ( ) => {
27- mockGit = {
28- paginate : jasmine . createSpy ( 'paginate' ) ,
29- issues : {
30- listLabelsForRepo : jasmine . createSpy ( 'listLabelsForRepo' ) ,
31- addLabels : jasmine . createSpy ( 'addLabels' ) ,
32- get : jasmine . createSpy ( 'get' ) ,
33- } ,
34- } ;
18+ mockGit = jasmine . createSpyObj ( 'Octokit' , [ 'paginate' , 'issues' , 'pulls' ] ) ;
19+ mockGit . issues = jasmine . createSpyObj ( 'issues' , [ 'addLabels' , 'get' ] ) ;
20+
21+ // Mock paginate to return the result of the promise if it's a list, or just execute the callback
22+ ( mockGit . paginate as jasmine . Spy ) . and . callFake ( ( fn : any , args : any ) => {
23+ if ( fn === mockGit . issues . listLabelsOnIssue ) {
24+ return Promise . resolve ( [ { name : 'area: core' } , { name : 'area: router' } , { name : 'bug' } ] ) ;
25+ }
26+ return Promise . resolve ( [ ] ) ;
27+ } ) ;
3528
36- mockGit . issues . addLabels . and . returnValue ( Promise . resolve ( { } ) ) ;
37- mockGit . issues . get . and . returnValue (
38- Promise . resolve ( {
39- data : {
40- title : 'Tough Issue' ,
41- body : 'Complex Body' ,
42- labels : [ ] ,
43- } ,
44- } ) ,
45- ) ;
46- mockGit . paginate . and . resolveTo ( [ { name : 'area: core' } , { name : 'area: router' } , { name : 'bug' } ] ) ;
29+ ( mockGit . issues . addLabels as unknown as jasmine . Spy ) . and . returnValue ( Promise . resolve ( { } ) ) ;
30+ getIssue = mockGit . issues . get as unknown as jasmine . Spy ;
31+ getIssue . and . resolveTo ( {
32+ data : {
33+ title : 'Tough Issue' ,
34+ body : 'Complex Body' ,
35+ labels : [ ] ,
36+ } ,
37+ } ) ;
4738
4839 mockAI = {
4940 models : jasmine . createSpyObj ( 'models' , [ 'generateContent' ] ) ,
5041 } ;
51- mockCore = jasmine . createSpyObj < typeof core > ( 'core' , [
52- 'getInput' ,
53- 'info' ,
54- 'error' ,
55- 'warning' ,
56- 'debug' ,
57- 'setFailed' ,
58- ] ) ;
59- mockCore . getInput . and . returnValue ( 'mock-ai-key' ) ;
60- mockCore . error . and . callFake ( console . error ) ;
61- mockCore . info . and . callFake ( console . info ) ;
62- mockCore . warning . and . callFake ( console . warn ) ;
63- mockCore . debug . and . callFake ( console . debug ) ;
64- mockCore . setFailed . and . callFake ( console . error ) ;
65-
66-
67- // We must cast the mock to Octokit because the mock only implements the subset used by the class.
68- // This is standard for mocking large interfaces like Octokit.
69- issueLabeling = new TestableIssueLabeling ( mockGit as unknown as Octokit , mockCore ) ;
70-
71- spyOn ( issueLabeling , 'getGenerativeAI' ) . and . returnValue ( mockAI ) ;
42+
43+ spyOn ( IssueLabeling . prototype , 'getGenerativeAI' ) . and . returnValue ( mockAI ) ;
44+ issueLabeling = new IssueLabeling ( ) ;
45+ issueLabeling . setGit ( mockGit as unknown as Octokit ) ;
7246 } ) ;
7347
7448 it ( 'should initialize labels correctly' , async ( ) => {
@@ -85,6 +59,7 @@ describe('IssueLabeling', () => {
8559 } ) ,
8660 ) ;
8761
62+ await issueLabeling . initialize ( ) ;
8863 await issueLabeling . run ( ) ;
8964
9065 expect ( mockGit . issues . addLabels ) . toHaveBeenCalledWith (
@@ -101,6 +76,7 @@ describe('IssueLabeling', () => {
10176 } ) ,
10277 ) ;
10378
79+ await issueLabeling . initialize ( ) ;
10480 await issueLabeling . run ( ) ;
10581
10682 expect ( mockGit . issues . addLabels ) . not . toHaveBeenCalled ( ) ;
@@ -113,28 +89,24 @@ describe('IssueLabeling', () => {
11389 } ) ,
11490 ) ;
11591
92+ await issueLabeling . initialize ( ) ;
11693 await issueLabeling . run ( ) ;
11794
11895 expect ( mockGit . issues . addLabels ) . not . toHaveBeenCalled ( ) ;
11996 } ) ;
12097
121- it ( 'should initialize and run with manual instantiation check' , ( ) => {
122- expect ( issueLabeling ) . toBeDefined ( ) ;
123- expect ( mockCore . getInput ) . not . toHaveBeenCalled ( ) ; // until run is called
124- } ) ;
125-
12698 it ( 'should skip labeling when issue already has an area label' , async ( ) => {
127- mockGit . issues . get . and . resolveTo ( {
99+ getIssue . and . resolveTo ( {
128100 data : {
129101 title : 'Tough Issue' ,
130102 body : 'Complex Body' ,
131103 labels : [ { name : 'area: core' } ] ,
132104 } ,
133105 } ) ;
106+ await issueLabeling . initialize ( ) ;
134107
135108 await issueLabeling . run ( ) ;
136109
137110 expect ( mockGit . issues . addLabels ) . not . toHaveBeenCalled ( ) ;
138- expect ( mockCore . info ) . toHaveBeenCalledWith ( 'Issue already has an area label. Skipping.' ) ;
139111 } ) ;
140112} ) ;
0 commit comments