@@ -527,4 +527,85 @@ describe('given a BrowserDataManager with mocked dependencies', () => {
527527 '[BrowserDataManager] Identify called after data manager was closed.' ,
528528 ) ;
529529 } ) ;
530+
531+ it ( 'retries initial polling until it succeeds' , async ( ) => {
532+ jest . useFakeTimers ( ) ;
533+ const context = Context . fromLDContext ( { kind : 'user' , key : 'test-user' } ) ;
534+ flagManager . loadCached . mockResolvedValue ( false ) ;
535+
536+ // Mock fetch to fail twice with 500 error, then succeed
537+ let callCount = 0 ;
538+ const mockedFetch = jest . fn ( ) . mockImplementation ( ( ) => {
539+ callCount += 1 ;
540+ if ( callCount <= 2 ) {
541+ return mockResponse ( '' , 500 ) ;
542+ }
543+ return mockResponse ( '{"flagA": true}' , 200 ) ;
544+ } ) ;
545+
546+ platform . requests . fetch = mockedFetch as typeof platform . requests . fetch ;
547+
548+ const identifyResolve = jest . fn ( ) ;
549+ const identifyReject = jest . fn ( ) ;
550+
551+ const identifyOptions : BrowserIdentifyOptions = { initialPollingRetries : 3 } ;
552+ const identifyPromise = dataManager . identify (
553+ identifyResolve ,
554+ identifyReject ,
555+ context ,
556+ identifyOptions ,
557+ ) ;
558+
559+ // Fast-forward through the retry delays (2 retries * 1000ms each)
560+ await jest . advanceTimersByTimeAsync ( 2000 ) ;
561+
562+ await identifyPromise ;
563+
564+ expect ( mockedFetch ) . toHaveBeenCalledTimes ( 3 ) ;
565+ expect ( identifyResolve ) . toHaveBeenCalled ( ) ;
566+ expect ( identifyReject ) . not . toHaveBeenCalled ( ) ;
567+ expect ( flagManager . init ) . toHaveBeenCalledWith (
568+ expect . anything ( ) ,
569+ expect . objectContaining ( { flagA : { flag : true , version : undefined } } ) ,
570+ ) ;
571+
572+ jest . useRealTimers ( ) ;
573+ } ) ;
574+
575+ it ( 'throws an error when initial polling reaches max retry limit' , async ( ) => {
576+ jest . useFakeTimers ( ) ;
577+ const context = Context . fromLDContext ( { kind : 'user' , key : 'test-user' } ) ;
578+ flagManager . loadCached . mockResolvedValue ( false ) ;
579+
580+ // Mock fetch to always fail with 500 error
581+ const mockedFetch = jest . fn ( ) . mockImplementation ( ( ) => {
582+ return mockResponse ( '' , 500 ) ;
583+ } ) ;
584+
585+ platform . requests . fetch = mockedFetch as typeof platform . requests . fetch ;
586+
587+ const identifyResolve = jest . fn ( ) ;
588+ const identifyReject = jest . fn ( ) ;
589+
590+ const identifyOptions : BrowserIdentifyOptions = { initialPollingRetries : 2 } ;
591+ const identifyPromise = dataManager . identify (
592+ identifyResolve ,
593+ identifyReject ,
594+ context ,
595+ identifyOptions ,
596+ ) ;
597+
598+ // Fast-forward through the retry delays (2 retries * 1000ms each)
599+ await jest . advanceTimersByTimeAsync ( 2000 ) ;
600+
601+ await identifyPromise ;
602+
603+ // Should attempt initial request + 2 retries = 3 total attempts
604+ expect ( mockedFetch ) . toHaveBeenCalledTimes ( 3 ) ;
605+ expect ( identifyResolve ) . not . toHaveBeenCalled ( ) ;
606+ expect ( identifyReject ) . toHaveBeenCalled ( ) ;
607+ expect ( identifyReject ) . toHaveBeenCalledWith ( expect . objectContaining ( { status : 500 } ) ) ;
608+
609+ jest . useRealTimers ( ) ;
610+ } ) ;
530611} ) ;
0 commit comments