From bd795a3e9f0f9cc6c36ac250b29d6df13a265526 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Fri, 12 Nov 2021 17:22:14 +0100 Subject: refactor(tabs): lay down infrastructure for multiple users (#864) * refactor(screen): support multiple mirrored clients * style(fmt): make rustfmt happy * style(clippy): make clippy happy * whitespace * github, y u no update CI?! * is this a cache issue? * is it the checkout cache? * no cache at all? * Debug * fix gototab * decoment * gototab none in wasm_vm * gototab none in wasm_vm * the fun never ends * tests(e2e): update infra and add multiple user mirroring test * refactor(tab): change structs in tabs and terminal panes to support multiple users * style(fmt): make rustfmt happy * style(fmt): make clippy happy --- src/tests/e2e/cases.rs | 1458 +++++++++++++------- src/tests/e2e/remote_runner.rs | 412 +++--- ...rtically_when_active_terminal_is_too_small.snap | 2 +- .../zellij__tests__e2e__cases__close_tab.snap | 50 +- ...ij__tests__e2e__cases__mirrored_sessions-2.snap | 29 + ...llij__tests__e2e__cases__mirrored_sessions.snap | 8 +- ...tests__e2e__cases__typing_exit_closes_pane.snap | 29 + 7 files changed, 1240 insertions(+), 748 deletions(-) create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__typing_exit_closes_pane.snap (limited to 'src') diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index aa8ad34b8..0198adfe0 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -75,8 +75,12 @@ pub fn starts_with_one_terminal() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("starts_with_one_terminal", fake_win_size) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for app to load", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -86,8 +90,13 @@ pub fn starts_with_one_terminal() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -99,8 +108,11 @@ pub fn split_terminals_vertically() { rows: 24, }; - let last_snapshot = RemoteRunner::new("split_terminals_vertically", fake_win_size) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { name: "Split pane to the right", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -114,8 +126,9 @@ pub fn split_terminals_vertically() { } step_is_complete }, - }) - .add_step(Step { + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for new pane to appear", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -125,8 +138,14 @@ pub fn split_terminals_vertically() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -134,49 +153,11 @@ pub fn split_terminals_vertically() { #[ignore] pub fn cannot_split_terminals_vertically_when_active_terminal_is_too_small() { let fake_win_size = Size { cols: 8, rows: 20 }; - let last_snapshot = RemoteRunner::new( - "cannot_split_terminals_vertically_when_active_terminal_is_too_small", - fake_win_size, - ) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Make sure only one pane appears", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) && remote_terminal.snapshot_contains("...") - { - // ... is the truncated tip line - step_is_complete = true; - } - step_is_complete - }, - }) - .run_all_steps(); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn scrolling_inside_a_pane() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let last_snapshot = RemoteRunner::new("scrolling_inside_a_pane", fake_win_size) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { name: "Split pane to the right", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -190,52 +171,109 @@ pub fn scrolling_inside_a_pane() { } step_is_complete }, - }) - .add_step(Step { - name: "Fill terminal with text", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // cursor is in the newly opened second pane - remote_terminal.send_key(format!("{:0<56}", "line1 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line2 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line3 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line4 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line5 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line6 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line7 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line8 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line9 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line10 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line11 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line12 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line13 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line14 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line15 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line16 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line17 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line18 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line19 ").as_bytes()); - remote_terminal.send_key(format!("{:0<57}", "line20 ").as_bytes()); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Scroll up inside pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { + name: "Make sure only one pane appears", + instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(118, 20) { - // all lines have been written to the pane - remote_terminal.send_key(&SCROLL_MODE); - remote_terminal.send_key(&SCROLL_UP_IN_SCROLL_MODE); + // if remote_terminal.cursor_position_is(3, 2) && remote_terminal.snapshot_contains("...") + if remote_terminal.cursor_position_is(3, 2) { + // ... is the truncated tip line step_is_complete = true; } step_is_complete }, - }) - .add_step(Step { + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; + assert_snapshot!(last_snapshot); +} + +#[test] +#[ignore] +pub fn scrolling_inside_a_pane() { + let fake_win_size = Size { + cols: 120, + rows: 24, + }; + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .retry_pause_ms(1000) // we need a longer retry period here because it takes some time to fill the pty buffer + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Fill terminal with text", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + let mut content_to_send = String::new(); + content_to_send.push_str(&format!("{:0<56}", "line1 ")); + content_to_send.push_str(&format!("{:0<58}", "line2 ")); + content_to_send.push_str(&format!("{:0<58}", "line3 ")); + content_to_send.push_str(&format!("{:0<58}", "line4 ")); + content_to_send.push_str(&format!("{:0<58}", "line5 ")); + content_to_send.push_str(&format!("{:0<58}", "line6 ")); + content_to_send.push_str(&format!("{:0<58}", "line7 ")); + content_to_send.push_str(&format!("{:0<58}", "line8 ")); + content_to_send.push_str(&format!("{:0<58}", "line9 ")); + content_to_send.push_str(&format!("{:0<58}", "line10 ")); + content_to_send.push_str(&format!("{:0<58}", "line11 ")); + content_to_send.push_str(&format!("{:0<58}", "line12 ")); + content_to_send.push_str(&format!("{:0<58}", "line13 ")); + content_to_send.push_str(&format!("{:0<58}", "line14 ")); + content_to_send.push_str(&format!("{:0<58}", "line15 ")); + content_to_send.push_str(&format!("{:0<58}", "line16 ")); + content_to_send.push_str(&format!("{:0<58}", "line17 ")); + content_to_send.push_str(&format!("{:0<58}", "line18 ")); + content_to_send.push_str(&format!("{:0<58}", "line19 ")); + content_to_send.push_str(&format!("{:0<57}", "line20 ")); + + remote_terminal.send_key(content_to_send.as_bytes()); + + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Scroll up inside pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(118, 20) { + // all lines have been written to the pane + remote_terminal.send_key(&SCROLL_MODE); + remote_terminal.send_key(&SCROLL_UP_IN_SCROLL_MODE); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for scroll to finish", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -247,8 +285,14 @@ pub fn scrolling_inside_a_pane() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -259,38 +303,44 @@ pub fn toggle_pane_fullscreen() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("toggle_pane_fullscreen", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Change newly opened pane to be fullscreen", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // cursor is in the newly opened second pane - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE); - // back to normal mode after toggling fullscreen - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Change newly opened pane to be fullscreen", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE); + // back to normal mode after toggling fullscreen + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for pane to become fullscreen", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -300,8 +350,14 @@ pub fn toggle_pane_fullscreen() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -312,38 +368,44 @@ pub fn open_new_tab() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("open_new_tab", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Open new tab", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // cursor is in the newly opened second pane - remote_terminal.send_key(&TAB_MODE); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Open new tab", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + remote_terminal.send_key(&TAB_MODE); + remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for new tab to open", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -357,50 +419,146 @@ pub fn open_new_tab() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } #[test] #[ignore] -pub fn close_pane() { +pub fn close_tab() { let fake_win_size = Size { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("close_pane", fake_win_size) - .add_step(Step { - name: "Split pane to the right", + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Open new tab", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + remote_terminal.send_key(&TAB_MODE); + remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); + // back to normal mode + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Close tab", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(3, 2) + && remote_terminal.tip_appears() + && remote_terminal.snapshot_contains("Tab #2") + && remote_terminal.status_bar_appears() + { + // cursor is in the newly opened second tab + remote_terminal.send_key(&TAB_MODE); + remote_terminal.send_key(&CLOSE_TAB_IN_TAB_MODE); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { + name: "Wait for tab to close", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) + if remote_terminal.cursor_position_is(3, 2) + && !remote_terminal.snapshot_contains("Tab #2") { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); + // cursor is in the first tab again step_is_complete = true; } step_is_complete }, - }) - .add_step(Step { - name: "Close pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // cursor is in the newly opened second pane - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&CLOSE_PANE_IN_PANE_MODE); - // back to normal mode after close - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; + assert_snapshot!(last_snapshot); +} + +#[test] +#[ignore] +pub fn close_pane() { + let fake_win_size = Size { + cols: 120, + rows: 24, + }; + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Close pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&CLOSE_PANE_IN_PANE_MODE); + // back to normal mode after close + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for pane to close", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -410,8 +568,14 @@ pub fn close_pane() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -422,8 +586,11 @@ pub fn exit_zellij() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("exit_zellij", fake_win_size) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { name: "Wait for app to load", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -434,8 +601,9 @@ pub fn exit_zellij() { } step_is_complete }, - }) - .add_step(Step { + }); + runner.run_all_steps(); + break runner.take_snapshot_after(Step { name: "Wait for app to exit", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -446,8 +614,8 @@ pub fn exit_zellij() { } step_is_complete }, - }) - .run_all_steps(); + }); + }; assert!(last_snapshot.contains("Bye from Zellij!")); } @@ -458,8 +626,11 @@ pub fn closing_last_pane_exits_zellij() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("closing_last_pane_exits_zellij", fake_win_size) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { name: "Close pane", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -471,8 +642,13 @@ pub fn closing_last_pane_exits_zellij() { } step_is_complete }, - }) - .add_step(Step { + }); + runner.run_all_steps(); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } + break runner.take_snapshot_after(Step { name: "Wait for app to exit", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -481,50 +657,122 @@ pub fn closing_last_pane_exits_zellij() { } step_is_complete }, - }) - .run_all_steps(); + }); + }; assert!(last_snapshot.contains("Bye from Zellij!")); } #[test] #[ignore] -pub fn resize_pane() { +pub fn typing_exit_closes_pane() { let fake_win_size = Size { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("resize_pane", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Resize pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Type exit", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + remote_terminal.send_key("e".as_bytes()); + remote_terminal.send_key("x".as_bytes()); + remote_terminal.send_key("i".as_bytes()); + remote_terminal.send_key("t".as_bytes()); + remote_terminal.send_key("\n".as_bytes()); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { + name: "Wait for pane to close", + instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // cursor is in the newly opened second pane - remote_terminal.send_key(&RESIZE_MODE); - remote_terminal.send_key(&RESIZE_LEFT_IN_RESIZE_MODE); - // back to normal mode after resizing - remote_terminal.send_key(&ENTER); + // if remote_terminal.cursor_position_is(3, 2) && remote_terminal.tip_appears() { + if remote_terminal.cursor_position_is(3, 2) && remote_terminal.tip_appears() { + // cursor is in the original pane step_is_complete = true; } step_is_complete }, - }) - .add_step(Step { + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; + assert_snapshot!(last_snapshot); +} + +#[test] +#[ignore] +pub fn resize_pane() { + let fake_win_size = Size { + cols: 120, + rows: 24, + }; + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Resize pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + remote_terminal.send_key(&RESIZE_MODE); + remote_terminal.send_key(&RESIZE_LEFT_IN_RESIZE_MODE); + // back to normal mode after resizing + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for pane to be resized", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -534,8 +782,14 @@ pub fn resize_pane() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -546,33 +800,39 @@ pub fn lock_mode() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("lock_mode", fake_win_size) - .add_step(Step { - name: "Enter lock mode", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&LOCK_MODE); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Send keys that should not be intercepted by the app", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("INTERFACE LOCKED") { - remote_terminal.send_key(&TAB_MODE); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - remote_terminal.send_key("abc".as_bytes()); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Enter lock mode", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&LOCK_MODE); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Send keys that should not be intercepted by the app", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.snapshot_contains("INTERFACE LOCKED") { + remote_terminal.send_key(&TAB_MODE); + remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); + remote_terminal.send_key("abc".as_bytes()); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for terminal to render sent keys", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -582,8 +842,14 @@ pub fn lock_mode() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -595,35 +861,41 @@ pub fn resize_terminal_window() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("resize_terminal_window", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Change terminal window size", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // new pane has been opened and focused - remote_terminal.change_size(100, 24); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Change terminal window size", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // new pane has been opened and focused + remote_terminal.change_size(100, 24); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "wait for terminal to be resized and app to be re-rendered", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -633,8 +905,14 @@ pub fn resize_terminal_window() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -645,60 +923,66 @@ pub fn detach_and_attach_session() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("detach_and_attach_session", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Send some text to the active pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // new pane has been opened and focused - remote_terminal.send_key("I am some text".as_bytes()); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Detach session", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(77, 2) { - remote_terminal.send_key(&SESSION_MODE); - remote_terminal.send_key(&DETACH_IN_SESSION_MODE); - // text has been entered - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Reattach session", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if !remote_terminal.status_bar_appears() { - // we don't see the toolbar, so we can assume we've already detached - remote_terminal.attach_to_original_session(); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Send some text to the active pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // new pane has been opened and focused + remote_terminal.send_key("I am some text".as_bytes()); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Detach session", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(77, 2) { + remote_terminal.send_key(&SESSION_MODE); + remote_terminal.send_key(&DETACH_IN_SESSION_MODE); + // text has been entered + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Reattach session", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if !remote_terminal.status_bar_appears() { + // we don't see the toolbar, so we can assume we've already detached + remote_terminal.attach_to_original_session(); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for session to be attached", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -708,8 +992,14 @@ pub fn detach_and_attach_session() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -721,8 +1011,13 @@ pub fn accepts_basic_layout() { rows: 24, }; let layout_file_name = "three-panes-with-nesting.yaml"; - let last_snapshot = RemoteRunner::new_with_layout("accepts_basic_layout", fake_win_size, layout_file_name) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new_with_layout(fake_win_size, layout_file_name); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for app to load", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -733,8 +1028,14 @@ pub fn accepts_basic_layout() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -746,34 +1047,40 @@ fn focus_pane_with_mouse() { rows: 24, }; - let last_snapshot = RemoteRunner::new("split_terminals_vertically", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Click left pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - remote_terminal.send_key(&normal_mouse_report(Position::new(5, 2), 0)); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Click left pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + remote_terminal.send_key(&normal_mouse_report(Position::new(5, 2), 0)); + step_is_complete = true; + } + step_is_complete + }, + }); + runner.run_all_steps(); + let last_snapshot = runner.take_snapshot_after(Step { name: "Wait for left pane to be focused", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; @@ -783,8 +1090,14 @@ fn focus_pane_with_mouse() { } step_is_complete }, - }) - .run_all_steps(); + }); + if runner.test_timed_out && test_attempts > 0 { + test_attempts -= 1; + continue; + } else { + break last_snapshot; + } + }; assert_snapshot!(last_snapshot); } @@ -795,66 +1108,73 @@ pub fn scrolling_inside_a_pane_with_mouse() { cols: 120, rows: 24, }; - let last_snapshot = RemoteRunner::new("scrolling_inside_a_pane_with_mouse", fake_win_size) - .add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - remote_terminal.send_key(&ENTER); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Fill terminal with text", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { - // cursor is in the newly opened second pane - remote_terminal.send_key(format!("{:0<56}", "line1 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line2 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line3 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line4 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line5 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line6 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line7 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line8 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line9 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line10 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line11 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line12 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line13 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line14 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line15 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line16 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line17 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line18 ").as_bytes()); - remote_terminal.send_key(format!("{:0<58}", "line19 ").as_bytes()); - remote_terminal.send_key(format!("{:0<57}", "line20 ").as_bytes()); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Scroll up inside pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(118, 20) { - // all lines have been written to the pane - remote_terminal.send_key(&normal_mouse_report(Position::new(2, 64), 64)); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { + let mut test_attempts = 10; + let last_snapshot = loop { + RemoteRunner::kill_running_sessions(fake_win_size); + drop(()); + let mut runner = RemoteRunner::new(fake_win_size) + .retry_pause_ms(1000) // we need a longer retry period here because it takes some time to fill the pty buffer + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() + && remote_terminal.cursor_position_is(3, 2) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Fill terminal with text", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + remote_terminal.send_key(format!("{:0<56}", "line1 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line2 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line3 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line4 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line5 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line6 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line7 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line8 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line9 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line10 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line11 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line12 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line13 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line14 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line15 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line16 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line17 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line18 ").as_bytes()); + remote_terminal.send_key(format!("{:0<58}", "line19 ").as_bytes()); + remote_terminal.send_key(format!("{:0<57}", "line20 ").as_bytes()); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Scroll up inside pane", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(118, 20) { + // all lines have been written to the pane + remote_terminal.send