@@ -51,3 +51,135 @@ describe("TaskPrStatusService.getTaskPrStatus (missing worktree directory)", ()
5151 expect ( gitService . getDiffStats ) . not . toHaveBeenCalled ( ) ;
5252 } ) ;
5353} ) ;
54+
55+ describe ( "TaskPrStatusService revalidation PR detection" , ( ) => {
56+ let service : TaskPrStatusService ;
57+ let gitService : {
58+ getPrStatus : ReturnType < typeof vi . fn > ;
59+ getDiffStats : ReturnType < typeof vi . fn > ;
60+ getGitSyncStatus : ReturnType < typeof vi . fn > ;
61+ getPrUrlForBranch : ReturnType < typeof vi . fn > ;
62+ getPrDetailsByUrl : ReturnType < typeof vi . fn > ;
63+ } ;
64+ let workspaceService : {
65+ getWorkspace : ReturnType < typeof vi . fn > ;
66+ emit : ReturnType < typeof vi . fn > ;
67+ } ;
68+ let workspaceRepo : {
69+ findByTaskId : ReturnType < typeof vi . fn > ;
70+ updatePrCache : ReturnType < typeof vi . fn > ;
71+ } ;
72+
73+ beforeEach ( ( ) => {
74+ vi . restoreAllMocks ( ) ;
75+ gitService = {
76+ getPrStatus : vi . fn ( ) ,
77+ getDiffStats : vi . fn ( ) . mockResolvedValue ( { filesChanged : 0 } ) ,
78+ getGitSyncStatus : vi . fn ( ) . mockResolvedValue ( { aheadOfDefault : 0 } ) ,
79+ getPrUrlForBranch : vi . fn ( ) ,
80+ getPrDetailsByUrl : vi . fn ( ) ,
81+ } ;
82+ workspaceService = { getWorkspace : vi . fn ( ) , emit : vi . fn ( ) } ;
83+ workspaceRepo = {
84+ findByTaskId : vi . fn ( ) . mockReturnValue ( { prUrl : null , prState : null } ) ,
85+ updatePrCache : vi . fn ( ) ,
86+ } ;
87+ service = new TaskPrStatusService (
88+ gitService as unknown as GitService ,
89+ workspaceRepo as unknown as IWorkspaceRepository ,
90+ workspaceService as unknown as WorkspaceService ,
91+ ) ;
92+ vi . spyOn ( fs , "existsSync" ) . mockReturnValue ( true ) ;
93+ } ) ;
94+
95+ it . each ( [
96+ {
97+ name : "detects a PR on a local task's current branch with no linked branch" ,
98+ taskId : "task-local" ,
99+ workspace : { mode : "local" , worktreePath : null , folderPath : "/repo" } ,
100+ prStatus : {
101+ prExists : true ,
102+ prState : "open" ,
103+ prUrl : "https://github.com/acme/repo/pull/7" ,
104+ isDraft : false ,
105+ } ,
106+ diffStats : { filesChanged : 0 } ,
107+ expectedRepoPath : "/repo" ,
108+ expectDiffStatsCalled : false ,
109+ expectedCache : {
110+ prUrl : "https://github.com/acme/repo/pull/7" ,
111+ prState : "open" ,
112+ } ,
113+ expectedEmit : {
114+ prUrl : "https://github.com/acme/repo/pull/7" ,
115+ prState : "open" ,
116+ } ,
117+ } ,
118+ {
119+ name : "caches no PR for a local task whose branch has none, without checking diff" ,
120+ taskId : "task-local" ,
121+ workspace : { mode : "local" , worktreePath : null , folderPath : "/repo" } ,
122+ prStatus : { prExists : false } ,
123+ diffStats : { filesChanged : 0 } ,
124+ expectedRepoPath : "/repo" ,
125+ expectDiffStatsCalled : false ,
126+ expectedCache : { prUrl : null , prState : null } ,
127+ expectedEmit : null ,
128+ } ,
129+ {
130+ name : "still reports a worktree task's local diff when no PR exists" ,
131+ taskId : "task-wt" ,
132+ workspace : { mode : "worktree" , worktreePath : "/wt" , folderPath : null } ,
133+ prStatus : { prExists : false } ,
134+ diffStats : { filesChanged : 3 } ,
135+ expectedRepoPath : "/wt" ,
136+ expectDiffStatsCalled : true ,
137+ expectedCache : { prUrl : null , prState : null } ,
138+ expectedEmit : null ,
139+ } ,
140+ ] ) (
141+ "$name" ,
142+ async ( {
143+ taskId,
144+ workspace,
145+ prStatus,
146+ diffStats,
147+ expectedRepoPath,
148+ expectDiffStatsCalled,
149+ expectedCache,
150+ expectedEmit,
151+ } ) => {
152+ workspaceService . getWorkspace . mockResolvedValue ( {
153+ ...workspace ,
154+ linkedBranch : null ,
155+ } ) ;
156+ gitService . getPrStatus . mockResolvedValue ( prStatus ) ;
157+ gitService . getDiffStats . mockResolvedValue ( diffStats ) ;
158+
159+ await service . getTaskPrStatus ( taskId , null ) ;
160+ await new Promise ( ( resolve ) => setImmediate ( resolve ) ) ;
161+
162+ expect ( gitService . getPrStatus ) . toHaveBeenCalledWith ( expectedRepoPath ) ;
163+ if ( expectDiffStatsCalled ) {
164+ expect ( gitService . getDiffStats ) . toHaveBeenCalledWith ( expectedRepoPath ) ;
165+ } else {
166+ expect ( gitService . getDiffStats ) . not . toHaveBeenCalled ( ) ;
167+ }
168+ expect ( workspaceRepo . updatePrCache ) . toHaveBeenCalledWith (
169+ taskId ,
170+ expectedCache ,
171+ ) ;
172+ if ( expectedEmit ) {
173+ expect ( workspaceService . emit ) . toHaveBeenCalledWith (
174+ "taskPrInfoChanged" ,
175+ {
176+ taskId,
177+ ...expectedEmit ,
178+ } ,
179+ ) ;
180+ } else {
181+ expect ( workspaceService . emit ) . not . toHaveBeenCalled ( ) ;
182+ }
183+ } ,
184+ ) ;
185+ } ) ;
0 commit comments