@@ -251,9 +251,120 @@ describe('retryResponseErrorHandler', () => {
251251 expect ( retryCondition ) . toHaveBeenCalledWith ( error ) ;
252252 } ) ;
253253
254- it ( 'should reject with rate limit error when x-ratelimit-remaining is 0' , async ( ) => {
254+ it ( 'should retry with delay when x-ratelimit-remaining is 0 and retry-after header is present ' , async ( ) => {
255255 const error = {
256256 config : { retryOnError : true , retryCount : 1 } ,
257+ response : {
258+ status : 429 ,
259+ headers : {
260+ 'x-ratelimit-remaining' : '0' ,
261+ 'retry-after' : '1' , // 1 second for faster testing
262+ } ,
263+ data : {
264+ error_message : 'Rate limit exceeded' ,
265+ error_code : 429 ,
266+ errors : null ,
267+ } ,
268+ } ,
269+ } ;
270+ const config = { retryLimit : 3 } ;
271+ const client = axios . create ( ) ;
272+
273+ // Mock successful response after retry
274+ mock . onAny ( ) . reply ( 200 , { success : true } ) ;
275+
276+ jest . useFakeTimers ( ) ;
277+
278+ const responsePromise = retryResponseErrorHandler ( error , config , client ) ;
279+
280+ // Fast-forward time by 1 second
281+ jest . advanceTimersByTime ( 1000 ) ;
282+
283+ const response : any = await responsePromise ;
284+
285+ expect ( response . status ) . toBe ( 200 ) ;
286+ expect ( response . data . success ) . toBe ( true ) ;
287+
288+ jest . useRealTimers ( ) ;
289+ } ) ;
290+
291+ it ( 'should retry with delay when x-ratelimit-remaining is 0 and x-ratelimit-reset header is present' , async ( ) => {
292+ const error = {
293+ config : { retryOnError : true , retryCount : 1 } ,
294+ response : {
295+ status : 429 ,
296+ headers : {
297+ 'x-ratelimit-remaining' : '0' ,
298+ 'x-ratelimit-reset' : Math . floor ( ( Date . now ( ) + 2000 ) / 1000 ) . toString ( ) , // 2 seconds from now
299+ } ,
300+ data : {
301+ error_message : 'Rate limit exceeded' ,
302+ error_code : 429 ,
303+ errors : null ,
304+ } ,
305+ } ,
306+ } ;
307+ const config = { retryLimit : 3 } ;
308+ const client = axios . create ( ) ;
309+
310+ // Mock successful response after retry
311+ mock . onAny ( ) . reply ( 200 , { success : true } ) ;
312+
313+ jest . useFakeTimers ( ) ;
314+
315+ const responsePromise = retryResponseErrorHandler ( error , config , client ) ;
316+
317+ // Fast-forward time by 3 seconds (2 + 1 buffer)
318+ jest . advanceTimersByTime ( 3000 ) ;
319+
320+ const response : any = await responsePromise ;
321+
322+ expect ( response . status ) . toBe ( 200 ) ;
323+ expect ( response . data . success ) . toBe ( true ) ;
324+
325+ jest . useRealTimers ( ) ;
326+ } ) ;
327+
328+ it ( 'should retry with default delay when x-ratelimit-remaining is 0 and no reset headers are present' , async ( ) => {
329+ const error = {
330+ config : { retryOnError : true , retryCount : 1 } ,
331+ response : {
332+ status : 429 ,
333+ headers : {
334+ 'x-ratelimit-remaining' : '0' ,
335+ } ,
336+ data : {
337+ error_message : 'Rate limit exceeded' ,
338+ error_code : 429 ,
339+ errors : null ,
340+ } ,
341+ } ,
342+ } ;
343+ const config = { retryLimit : 3 } ;
344+ const client = axios . create ( ) ;
345+
346+ // Mock successful response after retry
347+ mock . onAny ( ) . reply ( 200 , { success : true } ) ;
348+
349+ // Use fake timers to avoid waiting for 60 seconds
350+ jest . useFakeTimers ( ) ;
351+
352+ const responsePromise = retryResponseErrorHandler ( error , config , client ) ;
353+
354+ // Fast-forward time by 60 seconds
355+ jest . advanceTimersByTime ( 60000 ) ;
356+
357+ const response : any = await responsePromise ;
358+
359+ expect ( response . status ) . toBe ( 200 ) ;
360+ expect ( response . data . success ) . toBe ( true ) ;
361+
362+ jest . useRealTimers ( ) ;
363+ } ) ;
364+
365+ it ( 'should reject with rate limit error when x-ratelimit-remaining is 0 and retry limit is exceeded' , async ( ) => {
366+ const error = {
367+ config : { retryOnError : true , retryCount : 3 } , // Already at retry limit
257368 response : {
258369 status : 429 ,
259370 headers : {
0 commit comments