@@ -132,6 +132,42 @@ describe('withRetries', () => {
132132 expect ( result ) . toBe ( 'ok' ) ;
133133 } ) ;
134134
135+ it ( 'caps exponential backoff at maxDelay' , async ( ) => {
136+ const fn = vi
137+ . fn ( )
138+ . mockRejectedValueOnce ( { code : SimulationFailedRpcError . code } )
139+ . mockRejectedValueOnce ( { code : SimulationFailedRpcError . code } )
140+ . mockRejectedValueOnce ( { code : SimulationFailedRpcError . code } )
141+ . mockResolvedValue ( 'ok' ) ;
142+
143+ // delay=1000, exponential: 1000, 2000, 4000 — but maxDelay=2500 caps it
144+ const promise = withRetries ( fn , {
145+ backoff : 'exponential' ,
146+ delay : 1000 ,
147+ max : 3 ,
148+ maxDelay : 2500
149+ } ) ;
150+
151+ // First call fails immediately
152+ await vi . advanceTimersByTimeAsync ( 0 ) ;
153+ expect ( fn ) . toHaveBeenCalledTimes ( 1 ) ;
154+
155+ // Retry 0: delay = min(1000 * 2^0, 2500) = 1000ms
156+ await vi . advanceTimersByTimeAsync ( 1000 ) ;
157+ expect ( fn ) . toHaveBeenCalledTimes ( 2 ) ;
158+
159+ // Retry 1: delay = min(1000 * 2^1, 2500) = 2000ms
160+ await vi . advanceTimersByTimeAsync ( 2000 ) ;
161+ expect ( fn ) . toHaveBeenCalledTimes ( 3 ) ;
162+
163+ // Retry 2: delay = min(1000 * 2^2, 2500) = 2500ms (capped)
164+ await vi . advanceTimersByTimeAsync ( 2500 ) ;
165+ expect ( fn ) . toHaveBeenCalledTimes ( 4 ) ;
166+
167+ const result = await promise ;
168+ expect ( result ) . toBe ( 'ok' ) ;
169+ } ) ;
170+
135171 it ( 'clamps max retries to MAX_RETRIES' , async ( ) => {
136172 const fn = vi . fn ( ) . mockRejectedValue ( { code : SimulationFailedRpcError . code } ) ;
137173
0 commit comments