@@ -4,6 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
44import { maybeOfferUpdateBeforeDoctor } from "./doctor-update.js" ;
55
66const originalStdinIsTtyDescriptor = Object . getOwnPropertyDescriptor ( process . stdin , "isTTY" ) ;
7+ const originalStdoutIsTtyDescriptor = Object . getOwnPropertyDescriptor ( process . stdout , "isTTY" ) ;
78
89const mocks = vi . hoisted ( ( ) => ( {
910 createUpdateProgress : vi . fn ( ) ,
@@ -52,6 +53,10 @@ beforeEach(async () => {
5253 configurable : true ,
5354 value : true ,
5455 } ) ;
56+ Object . defineProperty ( process . stdout , "isTTY" , {
57+ configurable : true ,
58+ value : true ,
59+ } ) ;
5560} ) ;
5661
5762afterEach ( ( ) => {
@@ -61,6 +66,11 @@ afterEach(() => {
6166 } else {
6267 delete ( process . stdin as Partial < typeof process . stdin > ) . isTTY ;
6368 }
69+ if ( originalStdoutIsTtyDescriptor ) {
70+ Object . defineProperty ( process . stdout , "isTTY" , originalStdoutIsTtyDescriptor ) ;
71+ } else {
72+ delete ( process . stdout as Partial < typeof process . stdout > ) . isTTY ;
73+ }
6474} ) ;
6575
6676describe ( "maybeOfferUpdateBeforeDoctor" , ( ) => {
@@ -115,9 +125,42 @@ describe("maybeOfferUpdateBeforeDoctor", () => {
115125 await expect ( runOffer ( { root : "/repo/link" , confirm } ) ) . rejects . toThrow ( "update exploded" ) ;
116126
117127 expect ( mocks . runGatewayUpdate ) . toHaveBeenCalledWith ( expect . objectContaining ( { progress } ) ) ;
128+ expect ( mocks . createUpdateProgress ) . toHaveBeenCalledWith ( true ) ;
118129 expect ( stop ) . toHaveBeenCalledTimes ( 1 ) ;
119130 } ) ;
120131
132+ it ( "disables update progress when stdout is not a TTY" , async ( ) => {
133+ Object . defineProperty ( process . stdout , "isTTY" , {
134+ configurable : true ,
135+ value : false ,
136+ } ) ;
137+ vi . spyOn ( fs , "realpath" ) . mockImplementation ( async ( candidate ) => String ( candidate ) ) ;
138+ mocks . runCommandWithTimeout . mockResolvedValue ( {
139+ stdout : "/repo/link\n" ,
140+ stderr : "" ,
141+ code : 0 ,
142+ killed : false ,
143+ signal : null ,
144+ termination : "exit" ,
145+ noOutputTimedOut : false ,
146+ } ) ;
147+ mocks . runGatewayUpdate . mockResolvedValue ( {
148+ status : "skipped" ,
149+ mode : "git" ,
150+ root : "/repo/link" ,
151+ steps : [ ] ,
152+ durationMs : 0 ,
153+ } ) ;
154+
155+ const confirm = vi . fn ( ) . mockResolvedValue ( true ) ;
156+ await expect ( runOffer ( { root : "/repo/link" , confirm } ) ) . resolves . toEqual ( {
157+ updated : true ,
158+ handled : false ,
159+ } ) ;
160+
161+ expect ( mocks . createUpdateProgress ) . toHaveBeenCalledWith ( false ) ;
162+ } ) ;
163+
121164 it ( "keeps package-manager guidance when git reports a different checkout" , async ( ) => {
122165 const confirm = vi . fn ( ) ;
123166 vi . spyOn ( fs , "realpath" ) . mockImplementation ( async ( candidate ) => String ( candidate ) ) ;
0 commit comments