@@ -62,6 +62,182 @@ describe("protocol tests", () => {
6262 await transport . close ( ) ;
6363 expect ( oncloseMock ) . toHaveBeenCalled ( ) ;
6464 } ) ;
65+
66+ test ( "should reset timeout when progress notification is received" , async ( ) => {
67+ jest . useFakeTimers ( ) ;
68+
69+ await protocol . connect ( transport ) ;
70+ const request = { method : "example" , params : { } } ;
71+ const mockSchema : ZodType < { result : string } > = z . object ( {
72+ result : z . string ( ) ,
73+ } ) ;
74+
75+ const onProgressMock = jest . fn ( ) ;
76+ const requestPromise = protocol . request ( request , mockSchema , {
77+ timeout : 1000 , // Increased timeout for more reliable testing
78+ resetTimeoutOnProgress : true ,
79+ onprogress : onProgressMock ,
80+ } ) ;
81+
82+ // Advance time close to timeout
83+ jest . advanceTimersByTime ( 800 ) ;
84+
85+ // Send progress notification
86+ if ( transport . onmessage ) {
87+ transport . onmessage ( {
88+ jsonrpc : "2.0" ,
89+ method : "notifications/progress" ,
90+ params : {
91+ progressToken : 0 ,
92+ progress : 50 ,
93+ total : 100 ,
94+ } ,
95+ } ) ;
96+ }
97+
98+ // Run all pending promises to ensure progress handler is called
99+ await Promise . resolve ( ) ;
100+
101+ // Verify progress handler was called
102+ expect ( onProgressMock ) . toHaveBeenCalledWith ( {
103+ progress : 50 ,
104+ total : 100 ,
105+ } ) ;
106+
107+ // Send success response
108+ if ( transport . onmessage ) {
109+ transport . onmessage ( {
110+ jsonrpc : "2.0" ,
111+ id : 0 ,
112+ result : { result : "success" } ,
113+ } ) ;
114+ }
115+
116+ // Run all pending promises
117+ await Promise . resolve ( ) ;
118+
119+ await expect ( requestPromise ) . resolves . toEqual ( { result : "success" } ) ;
120+
121+ jest . useRealTimers ( ) ;
122+ } ) ;
123+
124+ test ( "should respect maxTotalTimeout" , async ( ) => {
125+ jest . useFakeTimers ( ) ;
126+
127+ await protocol . connect ( transport ) ;
128+ const request = { method : "example" , params : { } } ;
129+ const mockSchema : ZodType < { result : string } > = z . object ( {
130+ result : z . string ( ) ,
131+ } ) ;
132+
133+ const onProgressMock = jest . fn ( ) ;
134+ const requestPromise = protocol . request ( request , mockSchema , {
135+ timeout : 1000 ,
136+ maxTotalTimeout : 100 ,
137+ resetTimeoutOnProgress : true ,
138+ onprogress : onProgressMock ,
139+ } ) ;
140+
141+ // Advance time beyond maxTotalTimeout
142+ jest . advanceTimersByTime ( 150 ) ;
143+
144+ // Send progress notification after maxTotalTimeout
145+ if ( transport . onmessage ) {
146+ transport . onmessage ( {
147+ jsonrpc : "2.0" ,
148+ method : "notifications/progress" ,
149+ params : {
150+ progressToken : 0 ,
151+ progress : 50 ,
152+ total : 100 ,
153+ } ,
154+ } ) ;
155+ }
156+
157+ await expect ( requestPromise ) . rejects . toThrow ( "Maximum total timeout exceeded" ) ;
158+ expect ( onProgressMock ) . not . toHaveBeenCalled ( ) ;
159+
160+ jest . useRealTimers ( ) ;
161+ } ) ;
162+
163+ test ( "should timeout if no progress received within timeout period" , async ( ) => {
164+ jest . useFakeTimers ( ) ;
165+
166+ await protocol . connect ( transport ) ;
167+ const request = { method : "example" , params : { } } ;
168+ const mockSchema : ZodType < { result : string } > = z . object ( {
169+ result : z . string ( ) ,
170+ } ) ;
171+
172+ const requestPromise = protocol . request ( request , mockSchema , {
173+ timeout : 100 ,
174+ resetTimeoutOnProgress : true ,
175+ } ) ;
176+
177+ // Advance time beyond timeout
178+ jest . advanceTimersByTime ( 101 ) ;
179+
180+ await expect ( requestPromise ) . rejects . toThrow ( "Request timed out" ) ;
181+
182+ jest . useRealTimers ( ) ;
183+ } ) ;
184+
185+ test ( "should handle multiple progress notifications correctly" , async ( ) => {
186+ jest . useFakeTimers ( ) ;
187+
188+ await protocol . connect ( transport ) ;
189+ const request = { method : "example" , params : { } } ;
190+ const mockSchema : ZodType < { result : string } > = z . object ( {
191+ result : z . string ( ) ,
192+ } ) ;
193+
194+ const onProgressMock = jest . fn ( ) ;
195+ const requestPromise = protocol . request ( request , mockSchema , {
196+ timeout : 1000 ,
197+ resetTimeoutOnProgress : true ,
198+ onprogress : onProgressMock ,
199+ } ) ;
200+
201+ // Simulate multiple progress updates
202+ for ( let i = 1 ; i <= 3 ; i ++ ) {
203+ // Advance close to timeout
204+ jest . advanceTimersByTime ( 800 ) ;
205+
206+ // Send progress notification
207+ if ( transport . onmessage ) {
208+ transport . onmessage ( {
209+ jsonrpc : "2.0" ,
210+ method : "notifications/progress" ,
211+ params : {
212+ progressToken : 0 ,
213+ progress : i * 25 ,
214+ total : 100 ,
215+ } ,
216+ } ) ;
217+ }
218+
219+ // Verify progress handler was called
220+ await Promise . resolve ( ) ;
221+ expect ( onProgressMock ) . toHaveBeenNthCalledWith ( i , {
222+ progress : i * 25 ,
223+ total : 100 ,
224+ } ) ;
225+ }
226+
227+ // Send success response
228+ if ( transport . onmessage ) {
229+ transport . onmessage ( {
230+ jsonrpc : "2.0" ,
231+ id : 0 ,
232+ result : { result : "success" } ,
233+ } ) ;
234+ }
235+
236+ await Promise . resolve ( ) ;
237+ await expect ( requestPromise ) . resolves . toEqual ( { result : "success" } ) ;
238+
239+ jest . useRealTimers ( ) ;
240+ } ) ;
65241} ) ;
66242
67243describe ( "mergeCapabilities" , ( ) => {
0 commit comments