@@ -583,6 +583,94 @@ describe('Passport', () => {
583583 expect ( getUserMock ) . toBeCalledTimes ( 1 ) ;
584584 expect ( authLoginMock ) . toBeCalledTimes ( 1 ) ;
585585 } ) ;
586+
587+ it ( 'should debounce concurrent login calls and return the same result' , async ( ) => {
588+ getUserMock . mockReturnValue ( null ) ;
589+ authLoginMock . mockReturnValue ( mockUserImx ) ;
590+
591+ // Make multiple concurrent login calls
592+ const loginPromise1 = passport . login ( ) ;
593+ const loginPromise2 = passport . login ( ) ;
594+ const loginPromise3 = passport . login ( ) ;
595+
596+ // All promises should be the same reference
597+ expect ( loginPromise1 ) . toEqual ( loginPromise2 ) ;
598+ expect ( loginPromise2 ) . toEqual ( loginPromise3 ) ;
599+
600+ // Wait for all to complete
601+ const [ result1 , result2 , result3 ] = await Promise . all ( [
602+ loginPromise1 ,
603+ loginPromise2 ,
604+ loginPromise3 ,
605+ ] ) ;
606+
607+ // All results should be the same
608+ expect ( result1 ) . toEqual ( mockUserImx . profile ) ;
609+ expect ( result2 ) . toEqual ( mockUserImx . profile ) ;
610+ expect ( result3 ) . toEqual ( mockUserImx . profile ) ;
611+
612+ // AuthManager.login should only be called once despite multiple login calls
613+ expect ( authLoginMock ) . toBeCalledTimes ( 1 ) ;
614+ } ) ;
615+
616+ it ( 'should reset login promise after successful completion and allow new login calls' , async ( ) => {
617+ getUserMock . mockReturnValue ( null ) ;
618+ authLoginMock . mockReturnValue ( mockUserImx ) ;
619+
620+ // First login call
621+ const firstLoginResult = await passport . login ( ) ;
622+ expect ( firstLoginResult ) . toEqual ( mockUserImx . profile ) ;
623+
624+ // Second login call after first completes should create a new login process
625+ const secondLoginResult = await passport . login ( ) ;
626+ expect ( secondLoginResult ) . toEqual ( mockUserImx . profile ) ;
627+
628+ // AuthManager.login should be called twice (once for each login)
629+ expect ( authLoginMock ) . toBeCalledTimes ( 2 ) ;
630+ } ) ;
631+
632+ it ( 'should reset login promise after failed completion and allow new login calls' , async ( ) => {
633+ const error = new Error ( 'Login failed' ) ;
634+ getUserMock . mockReturnValue ( null ) ;
635+ authLoginMock . mockRejectedValue ( error ) ;
636+
637+ // First login call should fail
638+ await expect ( passport . login ( ) ) . rejects . toThrow ( error ) ;
639+
640+ // Second login call after first fails should create a new login process
641+ authLoginMock . mockReturnValue ( mockUserImx ) ;
642+ const secondLoginResult = await passport . login ( ) ;
643+ expect ( secondLoginResult ) . toEqual ( mockUserImx . profile ) ;
644+
645+ // AuthManager.login should be called twice (once for failed, once for successful)
646+ expect ( authLoginMock ) . toBeCalledTimes ( 2 ) ;
647+ } ) ;
648+
649+ it ( 'should debounce concurrent login calls even when they fail' , async ( ) => {
650+ const error = new Error ( 'Login failed' ) ;
651+ getUserMock . mockReturnValue ( null ) ;
652+ authLoginMock . mockRejectedValue ( error ) ;
653+
654+ // Make multiple concurrent login calls that will fail
655+ const [ loginPromise1 , loginPromise2 , loginPromise3 ] = [
656+ passport . login ( ) ,
657+ passport . login ( ) ,
658+ passport . login ( ) ,
659+ ] ;
660+
661+ // All promises should be the same reference
662+ expect ( loginPromise1 ) . toEqual ( loginPromise2 ) ;
663+ expect ( loginPromise2 ) . toEqual ( loginPromise3 ) ;
664+
665+ // All should reject with the same error
666+ try {
667+ await Promise . all ( [ loginPromise1 , loginPromise2 , loginPromise3 ] ) ;
668+ } catch ( e : unknown ) {
669+ expect ( e ) . toEqual ( error ) ;
670+ // AuthManager.login should only be called once despite multiple login calls
671+ expect ( authLoginMock ) . toBeCalledTimes ( 1 ) ;
672+ }
673+ } ) ;
586674 } ) ;
587675
588676 describe ( 'linkExternalWallet' , ( ) => {
0 commit comments