@@ -532,4 +532,84 @@ describe('useInfiniteScroll', () => {
532532 scrollHeightSpy . mockRestore ( ) ;
533533 clientHeightSpy . mockRestore ( ) ;
534534 } ) ;
535+
536+ test ( 'should auto loadMore after initial load when container is not full, and second request receives the latest finalData' , async ( ) => {
537+ setTargetInfo ( 'scrollTop' , 0 ) ;
538+ const scrollHeightSpy = vi . spyOn ( targetEl , 'scrollHeight' , 'get' ) . mockImplementation ( ( ) => 50 ) ;
539+ const clientHeightSpy = vi . spyOn ( targetEl , 'clientHeight' , 'get' ) . mockImplementation ( ( ) => 300 ) ;
540+
541+ let capturedLastData : any ;
542+ const service = vi . fn ( async ( lastData ?: any ) => {
543+ capturedLastData = lastData ;
544+ await sleep ( 1000 ) ;
545+ if ( ! lastData ) {
546+ return { list : [ 1 , 2 , 3 ] , nextId : 1 } ;
547+ }
548+ return { list : [ 4 , 5 , 6 ] } ;
549+ } ) ;
550+
551+ const { result } = setup ( service , {
552+ target : targetEl ,
553+ isNoMore : ( d ) => d ?. nextId === undefined ,
554+ } ) ;
555+
556+ // Wait for initial load to complete
557+ await act ( async ( ) => {
558+ vi . advanceTimersByTime ( 1000 ) ;
559+ } ) ;
560+
561+ // Container is not full, so scrollMethod should have auto-triggered loadMore
562+ expect ( result . current . loadingMore ) . toBe ( true ) ;
563+ // The second call must receive the up-to-date finalData (not the stale closure value)
564+ expect ( capturedLastData ) . toMatchObject ( { list : [ 1 , 2 , 3 ] , nextId : 1 } ) ;
565+
566+ await act ( async ( ) => {
567+ vi . advanceTimersByTime ( 1000 ) ;
568+ } ) ;
569+ expect ( result . current . data ?. list ) . toMatchObject ( [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
570+ expect ( result . current . noMore ) . toBe ( true ) ;
571+
572+ scrollHeightSpy . mockRestore ( ) ;
573+ clientHeightSpy . mockRestore ( ) ;
574+ } ) ;
575+
576+ test ( 'mutate should not trigger extra loadMore' , async ( ) => {
577+ setTargetInfo ( 'scrollTop' , 0 ) ;
578+ const scrollHeightSpy = vi . spyOn ( targetEl , 'scrollHeight' , 'get' ) . mockImplementation ( ( ) => 50 ) ;
579+ const clientHeightSpy = vi . spyOn ( targetEl , 'clientHeight' , 'get' ) . mockImplementation ( ( ) => 300 ) ;
580+
581+ const service = vi . fn ( mockRequest ) ;
582+ const { result } = setup ( service , {
583+ target : targetEl ,
584+ isNoMore : ( d ) => d ?. nextId === undefined ,
585+ } ) ;
586+
587+ // Wait for initial load to complete; this auto-triggers a second load
588+ await act ( async ( ) => {
589+ vi . advanceTimersByTime ( 1000 ) ;
590+ } ) ;
591+ // Wait for the auto-triggered second load to complete
592+ await act ( async ( ) => {
593+ vi . advanceTimersByTime ( 1000 ) ;
594+ } ) ;
595+ expect ( result . current . noMore ) . toBe ( true ) ;
596+
597+ const callCountAfterLoad = service . mock . calls . length ;
598+
599+ // Mutate with data that makes noMore false, so loadMore *would* fire if scrollMethod ran
600+ act ( ( ) => {
601+ result . current . mutate ( { list : [ 10 , 20 ] , nextId : 1 } ) ;
602+ } ) ;
603+
604+ // Wait for any effects to run
605+ await act ( async ( ) => {
606+ vi . advanceTimersByTime ( 100 ) ;
607+ } ) ;
608+
609+ // mutate should NOT trigger additional requests via scrollMethod
610+ expect ( service ) . toBeCalledTimes ( callCountAfterLoad ) ;
611+
612+ scrollHeightSpy . mockRestore ( ) ;
613+ clientHeightSpy . mockRestore ( ) ;
614+ } ) ;
535615} ) ;
0 commit comments