@@ -541,3 +541,105 @@ test('Should not refresh charts when tab becomes active if no dashboard refresh
541541
542542 expect ( onRefresh ) . not . toHaveBeenCalled ( ) ;
543543} ) ;
544+
545+ test ( 'Should not cause infinite refresh loop with nested tabs - regression test' , async ( ) => {
546+ jest . clearAllMocks ( ) ;
547+ const getChartIdsFromComponent = require ( 'src/dashboard/util/getChartIdsFromComponent' ) ;
548+ getChartIdsFromComponent . mockReset ( ) ;
549+ getChartIdsFromComponent . mockReturnValue ( [ 201 , 202 ] ) ;
550+
551+ const props = createProps ( ) ;
552+ props . renderType = 'RENDER_TAB_CONTENT' ;
553+ props . isComponentVisible = false ;
554+
555+ const initialState = {
556+ dashboardState : {
557+ lastRefreshTime : Date . now ( ) - 1000 , // Dashboard was refreshed recently
558+ tabActivationTimes : {
559+ 'TAB-YT6eNksV-' : Date . now ( ) - 5000 , // Tab was activated before refresh
560+ } ,
561+ } ,
562+ dashboardInfo : {
563+ id : 23 ,
564+ dash_edit_perm : true ,
565+ } ,
566+ } ;
567+
568+ const { rerender } = render ( < Tab { ...props } /> , {
569+ useRedux : true ,
570+ useDnd : true ,
571+ initialState,
572+ } ) ;
573+
574+ // Initial state - no refresh should happen
575+ expect ( onRefresh ) . not . toHaveBeenCalled ( ) ;
576+
577+ // Make tab visible - should trigger ONE refresh
578+ rerender ( < Tab { ...props } isComponentVisible /> ) ;
579+
580+ await waitFor (
581+ ( ) => {
582+ expect ( onRefresh ) . toHaveBeenCalledTimes ( 1 ) ;
583+ } ,
584+ { timeout : 500 } ,
585+ ) ;
586+
587+ // Clear the mock to track subsequent calls
588+ jest . clearAllMocks ( ) ;
589+
590+ // REGRESSION TEST: Multiple re-renders should NOT trigger additional refreshes
591+ // This simulates the infinite loop scenario that was happening with nested tabs
592+ for ( let i = 0 ; i < 5 ; i ++ ) {
593+ rerender ( < Tab { ...props } isComponentVisible /> ) ;
594+ await new Promise ( resolve => setTimeout ( resolve , 20 ) ) ;
595+ }
596+
597+ expect ( onRefresh ) . not . toHaveBeenCalled ( ) ;
598+ } ) ;
599+
600+ test ( 'Should use isLazyLoad flag for tab refreshes' , async ( ) => {
601+ jest . clearAllMocks ( ) ;
602+ const getChartIdsFromComponent = require ( 'src/dashboard/util/getChartIdsFromComponent' ) ;
603+ getChartIdsFromComponent . mockReset ( ) ;
604+ getChartIdsFromComponent . mockReturnValue ( [ 401 , 402 ] ) ;
605+
606+ const props = createProps ( ) ;
607+ props . renderType = 'RENDER_TAB_CONTENT' ;
608+ props . isComponentVisible = true ;
609+
610+ const initialState = {
611+ dashboardState : {
612+ lastRefreshTime : Date . now ( ) - 1000 , // Dashboard was refreshed recently
613+ tabActivationTimes : {
614+ 'TAB-YT6eNksV-' : Date . now ( ) - 5000 , // Tab was activated before refresh
615+ } ,
616+ } ,
617+ dashboardInfo : {
618+ id : 42 ,
619+ dash_edit_perm : true ,
620+ } ,
621+ } ;
622+
623+ render ( < Tab { ...props } /> , {
624+ useRedux : true ,
625+ useDnd : true ,
626+ initialState,
627+ } ) ;
628+
629+ // Tab should trigger refresh with isLazyLoad = true
630+ await waitFor (
631+ ( ) => {
632+ expect ( onRefresh ) . toHaveBeenCalled ( ) ;
633+ } ,
634+ { timeout : 500 } ,
635+ ) ;
636+
637+ // Verify that isLazyLoad flag is set to true for tab refreshes
638+ expect ( onRefresh ) . toHaveBeenCalledWith (
639+ [ 401 , 402 ] ,
640+ true , // force
641+ 0 , // interval
642+ 42 , // dashboardId
643+ true , // isLazyLoad should be true to prevent infinite loops
644+ ) ;
645+ } ) ;
0 commit comments