@@ -62,6 +62,182 @@ describe("protocol tests", () => {
62
62
await transport . close ( ) ;
63
63
expect ( oncloseMock ) . toHaveBeenCalled ( ) ;
64
64
} ) ;
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
+ } ) ;
65
241
} ) ;
66
242
67
243
describe ( "mergeCapabilities" , ( ) => {
0 commit comments