@@ -549,6 +549,144 @@ def test_widget_row_count_reflects_actual_data_available(
549549 assert widget .page_size == 2 # Respects the display option
550550
551551
552+ def test_widget_with_unknown_row_count_should_auto_navigate_to_last_page (
553+ session : bf .Session ,
554+ ):
555+ """
556+ Given a widget with unknown row count (row_count=None), when a user
557+ navigates beyond the available data and all data is loaded, then the
558+ widget should automatically navigate back to the last valid page.
559+ """
560+ from bigframes .display import TableWidget
561+
562+ # Create a small DataFrame with known content
563+ test_data = pd .DataFrame (
564+ {
565+ "id" : [0 , 1 , 2 , 3 , 4 ],
566+ "value" : ["row_0" , "row_1" , "row_2" , "row_3" , "row_4" ],
567+ }
568+ )
569+ bf_df = session .read_pandas (test_data )
570+
571+ with bf .option_context ("display.repr_mode" , "anywidget" , "display.max_rows" , 2 ):
572+ widget = TableWidget (bf_df )
573+
574+ # Manually set row_count to None to simulate unknown total
575+ widget .row_count = None
576+
577+ # Navigate to a page beyond available data (page 10)
578+ # With page_size=2 and 5 rows, valid pages are 0, 1, 2
579+ widget .page = 10
580+
581+ # Force data loading by accessing table_html
582+ _ = widget .table_html
583+
584+ # After all data is loaded, widget should auto-navigate to last valid page
585+ # Last valid page = ceil(5 / 2) - 1 = 2
586+ assert widget .page == 2
587+
588+ # Verify the displayed content is the last page
589+ html = widget .table_html
590+ assert "row_4" in html # Last row should be visible
591+ assert "row_0" not in html # First row should not be visible
592+
593+
594+ def test_widget_with_unknown_row_count_should_display_correct_ui_text (
595+ session : bf .Session ,
596+ ):
597+ """
598+ Given a widget with unknown row count, the JavaScript frontend should
599+ display appropriate text indicating the total is unknown.
600+ """
601+ from bigframes .display import TableWidget
602+
603+ test_data = pd .DataFrame (
604+ {
605+ "id" : [0 , 1 , 2 ],
606+ "value" : ["a" , "b" , "c" ],
607+ }
608+ )
609+ bf_df = session .read_pandas (test_data )
610+
611+ with bf .option_context ("display.repr_mode" , "anywidget" , "display.max_rows" , 2 ):
612+ widget = TableWidget (bf_df )
613+
614+ # Set row_count to None
615+ widget .row_count = None
616+
617+ # Verify row_count is None (not 0)
618+ assert widget .row_count is None
619+
620+ # The widget should still function normally
621+ assert widget .page == 0
622+ assert widget .page_size == 2
623+
624+
625+ def test_widget_with_unknown_row_count_should_allow_forward_navigation (
626+ session : bf .Session ,
627+ ):
628+ """
629+ Given a widget with unknown row count, users should be able to navigate
630+ forward until they reach the end of available data.
631+ """
632+ from bigframes .display import TableWidget
633+
634+ test_data = pd .DataFrame (
635+ {
636+ "id" : [0 , 1 , 2 , 3 , 4 , 5 ],
637+ "value" : ["p0_r0" , "p0_r1" , "p1_r0" , "p1_r1" , "p2_r0" , "p2_r1" ],
638+ }
639+ )
640+ bf_df = session .read_pandas (test_data )
641+
642+ with bf .option_context ("display.repr_mode" , "anywidget" , "display.max_rows" , 2 ):
643+ widget = TableWidget (bf_df )
644+ widget .row_count = None
645+
646+ # Navigate to page 1
647+ widget .page = 1
648+ html = widget .table_html
649+ assert "p1_r0" in html
650+ assert "p1_r1" in html
651+
652+ # Navigate to page 2
653+ widget .page = 2
654+ html = widget .table_html
655+ assert "p2_r0" in html
656+ assert "p2_r1" in html
657+
658+ # Navigate beyond available data (page 5)
659+ widget .page = 5
660+ _ = widget .table_html
661+
662+ # Should auto-navigate back to last valid page (page 2)
663+ assert widget .page == 2
664+
665+
666+ def test_widget_with_unknown_row_count_empty_dataframe (
667+ session : bf .Session ,
668+ ):
669+ """
670+ Given an empty DataFrame with unknown row count, the widget should
671+ stay on page 0 and display empty content.
672+ """
673+ from bigframes .display import TableWidget
674+
675+ empty_data = pd .DataFrame (columns = ["id" , "value" ])
676+ bf_df = session .read_pandas (empty_data )
677+
678+ with bf .option_context ("display.repr_mode" , "anywidget" ):
679+ widget = TableWidget (bf_df )
680+ widget .row_count = None
681+
682+ # Attempt to navigate to page 5
683+ widget .page = 5
684+ _ = widget .table_html
685+
686+ # Should stay on page 0 for empty DataFrame
687+ assert widget .page == 0
688+
689+
552690# TODO(shuowei): Add tests for custom index and multiindex
553691# This may not be necessary for the SQL Cell use case but should be
554692# considered for completeness.
0 commit comments