@@ -1025,7 +1025,11 @@ mod tests {
10251025 use std:: rc:: Rc ;
10261026
10271027 use chrono:: { DateTime , Local , NaiveDateTime } ;
1028- use ratatui:: crossterm:: event:: { KeyCode , KeyEvent } ;
1028+ use ratatui:: {
1029+ backend:: TestBackend ,
1030+ crossterm:: event:: { KeyCode , KeyEvent } ,
1031+ Terminal ,
1032+ } ;
10291033
10301034 use super :: * ;
10311035 use crate :: {
@@ -1208,6 +1212,66 @@ mod tests {
12081212 assert_object_selected ( & app, "baz.txt" ) ;
12091213 }
12101214
1215+ #[ tokio:: test]
1216+ async fn object_list_refresh_keeps_scroll_offset (
1217+ ) -> std:: result:: Result < ( ) , core:: convert:: Infallible > {
1218+ let ( mut app, _rx) = app ( ) . await ;
1219+ let object_key = ObjectKey :: bucket ( "test-bucket" ) ;
1220+ let items = ( 1 ..=16 )
1221+ . map ( |i| object_file_item ( & format ! ( "file{i}.txt" ) ) )
1222+ . collect ( ) ;
1223+
1224+ app. page_stack . push ( Page :: of_object_list (
1225+ items,
1226+ object_key. clone ( ) ,
1227+ Rc :: clone ( & app. ctx ) ,
1228+ app. tx . clone ( ) ,
1229+ ) ) ;
1230+ app. is_loading = false ;
1231+
1232+ let mut terminal = setup_terminal ( ) ?;
1233+ render_app ( & mut app, & mut terminal) ?;
1234+
1235+ for _ in 0 ..8 {
1236+ app. page_stack . current_page_mut ( ) . handle_user_events (
1237+ vec ! [ UserEvent :: ObjectListDown ] ,
1238+ KeyEvent :: from ( KeyCode :: Char ( 'j' ) ) ,
1239+ ) ;
1240+ }
1241+
1242+ let reloaded_items = vec ! [
1243+ object_file_item( "file1.txt" ) ,
1244+ object_file_item( "file2.txt" ) ,
1245+ object_file_item( "file3.txt" ) ,
1246+ object_file_item( "file4.txt" ) ,
1247+ object_file_item( "file5.txt" ) ,
1248+ object_file_item( "file6.txt" ) ,
1249+ object_file_item( "file7.txt" ) ,
1250+ object_file_item( "file8.txt" ) ,
1251+ object_file_item( "file8.5.txt" ) ,
1252+ object_file_item( "file9.txt" ) ,
1253+ object_file_item( "file10.txt" ) ,
1254+ object_file_item( "file11.txt" ) ,
1255+ object_file_item( "file12.txt" ) ,
1256+ object_file_item( "file13.txt" ) ,
1257+ object_file_item( "file14.txt" ) ,
1258+ object_file_item( "file15.txt" ) ,
1259+ object_file_item( "file16.txt" ) ,
1260+ ] ;
1261+
1262+ app. complete_reload_objects ( Ok ( CompleteReloadObjectsResult {
1263+ items : reloaded_items,
1264+ object_key,
1265+ } ) ) ;
1266+ render_app ( & mut app, & mut terminal) ?;
1267+
1268+ assert_eq ! ( app. page_stack. len( ) , 1 ) ;
1269+ assert_object_selected ( & app, "file9.txt" ) ;
1270+ assert_object_list_position ( & app, 9 , 5 ) ;
1271+
1272+ Ok ( ( ) )
1273+ }
1274+
12111275 async fn app ( ) -> ( App , tokio:: sync:: mpsc:: UnboundedReceiver < AppEventType > ) {
12121276 let client = Client :: new (
12131277 None ,
@@ -1304,6 +1368,14 @@ mod tests {
13041368 ) ;
13051369 }
13061370
1371+ fn render_app (
1372+ app : & mut App ,
1373+ terminal : & mut Terminal < TestBackend > ,
1374+ ) -> std:: result:: Result < ( ) , core:: convert:: Infallible > {
1375+ terminal. draw ( |f| app. render ( f) ) ?;
1376+ Ok ( ( ) )
1377+ }
1378+
13071379 fn assert_bucket_selected ( app : & App , expected : & str ) {
13081380 match app. page_stack . current_page ( ) {
13091381 Page :: BucketList ( page) => assert_eq ! ( page. current_selected_item( ) . name, expected) ,
@@ -1318,6 +1390,17 @@ mod tests {
13181390 }
13191391 }
13201392
1393+ fn assert_object_list_position ( app : & App , selected : usize , offset : usize ) {
1394+ match app. page_stack . current_page ( ) {
1395+ Page :: ObjectList ( page) => {
1396+ let list_state = page. list_state ( ) ;
1397+ assert_eq ! ( list_state. selected, selected) ;
1398+ assert_eq ! ( list_state. offset, offset) ;
1399+ }
1400+ page => panic ! ( "Invalid page: {page:?}" ) ,
1401+ }
1402+ }
1403+
13211404 fn assert_bucket_names ( app : & App , expected : & [ & str ] ) {
13221405 let bucket_names = app
13231406 . app_objects
@@ -1361,4 +1444,11 @@ mod tests {
13611444 e_tag : String :: new ( ) ,
13621445 }
13631446 }
1447+
1448+ fn setup_terminal ( ) -> std:: result:: Result < Terminal < TestBackend > , core:: convert:: Infallible > {
1449+ let backend = TestBackend :: new ( 80 , 12 ) ;
1450+ let mut terminal = Terminal :: new ( backend) ?;
1451+ terminal. clear ( ) ?;
1452+ Ok ( terminal)
1453+ }
13641454}
0 commit comments