@@ -118,6 +118,57 @@ describe('fetchWithRetry', () => {
118118 expect ( fetch ) . toHaveBeenCalledOnce ( ) ;
119119 } ) ;
120120
121+ it ( 'retries when the internal request timeout aborts fetch' , async ( ) => {
122+ vi . mocked ( fetch )
123+ . mockImplementationOnce (
124+ ( _url : RequestInfo | URL , options ?: RequestInit ) =>
125+ new Promise < Response > ( ( _resolve , reject ) => {
126+ options ?. signal ?. addEventListener (
127+ 'abort' ,
128+ ( ) => reject ( new DOMException ( 'Timed out' , 'AbortError' ) ) ,
129+ { once : true }
130+ ) ;
131+ } )
132+ )
133+ . mockResolvedValueOnce ( new Response ( 'ok' , { status : 200 } ) ) ;
134+
135+ const promise = fetchWithRetry ( 'https://api.github.com/test' , { } , 0 , 100 ) ;
136+
137+ await vi . advanceTimersByTimeAsync ( 100 ) ;
138+ await vi . advanceTimersByTimeAsync ( 500 ) ;
139+
140+ const res = await promise ;
141+ expect ( res . status ) . toBe ( 200 ) ;
142+ expect ( fetch ) . toHaveBeenCalledTimes ( 2 ) ;
143+ } ) ;
144+
145+ it ( 'throws a timeout error after internal timeout retries are exhausted' , async ( ) => {
146+ vi . mocked ( fetch ) . mockImplementation (
147+ ( _url : RequestInfo | URL , options ?: RequestInit ) =>
148+ new Promise < Response > ( ( _resolve , reject ) => {
149+ options ?. signal ?. addEventListener (
150+ 'abort' ,
151+ ( ) => reject ( new DOMException ( 'Timed out' , 'AbortError' ) ) ,
152+ { once : true }
153+ ) ;
154+ } )
155+ ) ;
156+
157+ const promise = fetchWithRetry ( 'https://api.github.com/test' , { } , 0 , 100 ) ;
158+ const expectation = expect ( promise ) . rejects . toThrow ( 'GitHub API request timed out after 0.1s' ) ;
159+
160+ await vi . advanceTimersByTimeAsync ( 100 ) ;
161+ await vi . advanceTimersByTimeAsync ( 500 ) ;
162+ await vi . advanceTimersByTimeAsync ( 100 ) ;
163+ await vi . advanceTimersByTimeAsync ( 1000 ) ;
164+ await vi . advanceTimersByTimeAsync ( 100 ) ;
165+ await vi . advanceTimersByTimeAsync ( 2000 ) ;
166+ await vi . advanceTimersByTimeAsync ( 100 ) ;
167+
168+ await expectation ;
169+ expect ( fetch ) . toHaveBeenCalledTimes ( 4 ) ;
170+ } ) ;
171+
121172 it ( 'retries on 429 with numeric retry-after' , async ( ) => {
122173 vi . mocked ( fetch )
123174 . mockResolvedValueOnce ( new Response ( null , { status : 429 , headers : { 'retry-after' : '2' } } ) )
0 commit comments