diff options
| author | Aram Drevekenin <aram@poor.dev> | 2026-06-16 15:44:22 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-16 15:44:22 +0200 |
| commit | 8c7e41c9aaafc44520380a2c86db517fde54ad31 (patch) | |
| tree | d54bb40aef913c07f2142bd835dfa47d09fae5af /src/tests | |
| parent | Mobile layout (#5241) (diff) | |
| download | sl0ppij-8c7e41c9aaafc44520380a2c86db517fde54ad31.tar.gz sl0ppij-8c7e41c9aaafc44520380a2c86db517fde54ad31.tar.xz sl0ppij-8c7e41c9aaafc44520380a2c86db517fde54ad31.zip | |
chore: new test infra (#5269)
* initial implementation
* refactoring and cleanups
* port basic e2e tests
* fix tab rotation
* migrate client and mouse tests
* migrate the rest of the tests
* remove old e2e tests
* rustfmt
* add e2e note
* fix stale test
* fix: cross platform locking/cleanup
* fix: change mode race discovered by tests
* rustfmt
* fix: attach/detach race in tests
* fix plugin test assertion
* add pr
Diffstat (limited to 'src/tests')
| -rw-r--r-- | src/tests/e2e/cases.rs | 2531 | ||||
| -rw-r--r-- | src/tests/e2e/mod.rs | 1 | ||||
| -rw-r--r-- | src/tests/e2e/remote_runner.rs | 503 | ||||
| -rw-r--r-- | src/tests/e2e/steps.rs | 152 |
4 files changed, 7 insertions, 3180 deletions
diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index 854e1c93..c20eb2c8 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -1,3 +1,10 @@ +/* + * + * NOTE: These tests are very heavy and are used as smoke tests just to verify the app is working + * end-to-end. Avoid adding new ones, preferring instead to use the zellij-integration-tests module + * it tests the app as a whole, only mocking the OS interaction parts + * +*/ #![allow(unused)] use insta::assert_snapshot; @@ -12,13 +19,6 @@ use regex::Regex; use std::fmt::Write; use std::path::Path; -use crate::tests::e2e::steps::{ - check_focus_on_second_tab, check_second_tab_opened, check_third_tab_is_left_wrapped, - check_third_tab_is_right_wrapped, check_third_tab_moved_left, - check_third_tab_moved_to_beginning, check_third_tab_opened, move_tab_left, move_tab_right, - new_tab, switch_focus_to_left_tab, type_second_tab_content, -}; - use super::remote_runner::{RemoteRunner, RemoteTerminal, Step}; pub const QUIT: [u8; 1] = [17]; // ctrl-q @@ -79,18 +79,6 @@ pub const SLEEP: [u8; 0] = []; pub const SECOND_TAB_CONTENT: [u8; 14] = [84, 97, 98, 32, 35, 50, 32, 99, 111, 110, 116, 101, 110, 116]; // Tab #2 content -pub fn sgr_mouse_report(position: Position, button: u8) -> Vec<u8> { - // button: (release is with lower case m, not supported here yet) - // 0 => left click - // 2 => right click - // 64 => scroll up - // 65 => scroll down - let Position { line, column } = position; - format!("\u{1b}[<{};{};{}M", button, column.0, line.0) - .as_bytes() - .to_vec() -} - // what we do here is adjust snapshots for various race conditions that should hopefully be // temporary until we can fix them - when adding stuff here, please add a detailed comment // explaining the race condition and what needs to be done to solve it @@ -158,662 +146,6 @@ pub fn starts_with_one_terminal() { #[test] #[ignore] -pub fn split_terminals_vertically() { - 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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - step_is_complete = true; - } - step_is_complete - }, - }); - 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; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn cannot_split_terminals_vertically_when_active_terminal_is_too_small() { - let fake_win_size = Size { cols: 8, rows: 20 }; - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - 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.cursor_position_is(3, 2) { - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - // back to normal mode after split - step_is_complete = true; - } - step_is_complete - }, - }); - 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(3, 2) { - // ... is the truncated tip line - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.load_fixture("e2e/scrolling_inside_a_pane"); - 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(63, 21) - && remote_terminal.snapshot_contains("line21") - && remote_terminal.status_bar_appears() - { - // all lines have been written to the pane - remote_terminal.send_key(&SCROLL_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - 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; - if remote_terminal.cursor_position_is(63, 21) - && remote_terminal.snapshot_contains("line3 ") - && remote_terminal.snapshot_contains("SCROLL: 1/3") - && remote_terminal.snapshot_contains("PgDn|PgUp") - { - // keyboard scrolls up 1 line, scrollback is 4 lines: cat command + 2 extra lines from fixture + prompt - // PgDn|PgUp only appears in the scroll mode status bar, confirming we're still in scroll mode - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn toggle_pane_fullscreen() { - 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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE); - 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; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("LOCK") - { - // cursor is in full screen pane now - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn open_new_tab() { - 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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_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 new tab to open", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("Tab #2") - && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second tab - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn close_tab() { - 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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - 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.snapshot_contains("Tab #2") - && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second tab - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - 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.snapshot_contains("Tab #1") - && !remote_terminal.snapshot_contains("Tab #2") - { - // cursor is in the first tab again - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - assert!(last_snapshot.contains("Tab #1")); - assert!(!last_snapshot.contains("Tab #2")); -} - -#[test] -#[ignore] -pub fn move_tab_to_left() { - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size()); - let mut runner = RemoteRunner::new(fake_win_size()) - .add_step(new_tab()) - .add_step(check_second_tab_opened()) - .add_step(new_tab()) - .add_step(check_third_tab_opened()) // should have Tab#1 >> Tab#2 >> Tab#3 (focused on Tab#3) - .add_step(move_tab_left()); // now, it should be Tab#1 >> Tab#3 >> Tab#2 - - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(check_third_tab_moved_left()); - if !runner.test_timed_out || test_attempts == 0 { - break last_snapshot; - } - test_attempts -= 1; - }; - assert_snapshot!(account_for_races_in_snapshot(last_snapshot)); -} - -fn fake_win_size() -> Size { - Size { - cols: 120, - rows: 24, - } -} - -#[test] -#[ignore] -pub fn move_tab_to_right() { - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size()); - let mut runner = RemoteRunner::new(fake_win_size()) - .add_step(new_tab()) - .add_step(check_second_tab_opened()) - .add_step(type_second_tab_content()) // allows verifying the focus later - .add_step(new_tab()) - .add_step(check_third_tab_opened()) - .add_step(switch_focus_to_left_tab()) - .add_step(check_focus_on_second_tab()) // should have Tab#1 >> Tab#2 >> Tab#3 (focused on Tab#2) - .add_step(move_tab_right()); // now, it should be Tab#1 >> Tab#3 >> Tab#2 - - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(check_third_tab_moved_left()); - if !runner.test_timed_out || test_attempts == 0 { - break last_snapshot; - } - test_attempts -= 1; - }; - assert_snapshot!(account_for_races_in_snapshot(last_snapshot)); -} - -#[test] -#[ignore] -pub fn move_tab_to_left_until_it_wraps_around() { - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size()); - let mut runner = RemoteRunner::new(fake_win_size()) - .add_step(new_tab()) - .add_step(check_second_tab_opened()) - .add_step(new_tab()) - .add_step(check_third_tab_opened()) - .add_step(move_tab_left()) - .add_step(check_third_tab_moved_left()) - .add_step(move_tab_left()) - .add_step(check_third_tab_moved_to_beginning()) // should have Tab#3 >> Tab#1 >> Tab#2 (focused on Tab#3) - .add_step(move_tab_left()); // now, it should be Tab#2 >> Tab#1 >> Tab#3 - - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(check_third_tab_is_left_wrapped()); - if !runner.test_timed_out || test_attempts == 0 { - break last_snapshot; - } - test_attempts -= 1; - }; - assert_snapshot!(account_for_races_in_snapshot(last_snapshot)); -} - -#[test] -#[ignore] -pub fn move_tab_to_right_until_it_wraps_around() { - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size()); - let mut runner = RemoteRunner::new(fake_win_size()) - .add_step(new_tab()) - .add_step(check_second_tab_opened()) - .add_step(new_tab()) - .add_step(check_third_tab_opened()) // should have Tab#1 >> Tab#2 >> Tab#3 (focused on Tab#3) - .add_step(move_tab_right()); // now, it should be Tab#3 >> Tab#2 >> Tab#1 - - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(check_third_tab_is_right_wrapped()); - if !runner.test_timed_out || test_attempts == 0 { - break last_snapshot; - } - test_attempts -= 1; - }; - assert_snapshot!(account_for_races_in_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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&CLOSE_PANE_IN_PANE_MODE); - 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(3, 2) && remote_terminal.status_bar_appears() - { - // cursor is in the original pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn exit_zellij() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let last_snapshot = { - RemoteRunner::kill_running_sessions(fake_win_size); - 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; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&QUIT); - step_is_complete = true; - } - step_is_complete - }, - }); - runner.run_all_steps(); - runner.take_snapshot_after(Step { - name: "Wait for app to exit", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if !remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Bye from Zellij!") - { - step_is_complete = true; - } - step_is_complete - }, - }) - }; - assert!(last_snapshot.contains("Bye from Zellij!")); -} - -#[test] -#[ignore] -pub fn closing_last_pane_exits_zellij() { - 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); - 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; - if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&CLOSE_PANE_IN_PANE_MODE); - step_is_complete = true; - } - step_is_complete - }, - }); - 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; - if remote_terminal.snapshot_contains("Bye from Zellij!") { - step_is_complete = true; - } - step_is_complete - }, - }); - }; - assert!(last_snapshot.contains("Bye from Zellij!")); -} - -#[test] -#[ignore] pub fn typing_exit_closes_pane() { let fake_win_size = Size { cols: 120, @@ -885,138 +217,6 @@ pub fn typing_exit_closes_pane() { #[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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&RESIZE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&RESIZE_LEFT_IN_RESIZE_MODE); - // back to normal mode - 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; - if remote_terminal.cursor_position_is(57, 2) - && remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("LOCK") - { - // pane has been resized - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn lock_mode() { - 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); - 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("PANE") { - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - 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; - if remote_terminal.cursor_position_is(7, 2) { - // text has been entered into the only terminal pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] pub fn resize_terminal_window() { // this checks the resizing of the whole terminal window (reaction to SIGWINCH) and not just one pane let fake_win_size = Size { @@ -1082,101 +282,6 @@ pub fn resize_terminal_window() { #[test] #[ignore] -pub fn detach_and_attach_session() { - 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); - let mut runner = RemoteRunner::new_mirrored_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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_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); - std::thread::sleep(std::time::Duration::from_millis(100)); - 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() - && remote_terminal.snapshot_contains("Bye from Zellij!") - { - // we don't see the toolbar and Zellij's exit message is visible, - // so Zellij has fully exited and the server is ready to accept connections - 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; - if remote_terminal.ctrl_plus_appears() - && remote_terminal.cursor_position_is(77, 2) - && !remote_terminal.snapshot_contains("Detach") - { - // we're back inside the session - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] pub fn quit_and_resurrect_session() { let fake_win_size = Size { cols: 120, @@ -1233,1175 +338,6 @@ pub fn quit_and_resurrect_session() { #[test] #[ignore] -pub fn quit_and_resurrect_session_with_viewport_serialization() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let layout_name = "layout_for_resurrection.kdl"; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new_mirrored_session_with_layout_and_viewport_serialization( - fake_win_size, - layout_name, - ) - .add_step(Step { - name: "Wait for session to be serialized", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Waiting to run: top") { - std::thread::sleep(std::time::Duration::from_millis(5000)); // wait for - // serialization - remote_terminal.send_key(&QUIT); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Resurrect session by attaching", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Bye from Zellij!") { - 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 resurrected", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.snapshot_contains("(FLOATING PANES VISIBLE)") - && remote_terminal.status_bar_appears() - && remote_terminal.tab_bar_appears() - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn status_bar_loads_custom_keybindings() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let config_file_name = "changed_keys.kdl"; - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new_with_config(fake_win_size, config_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; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("LOCK") - { - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -fn focus_pane_with_mouse() { - 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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - { - remote_terminal.send_key(&sgr_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; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("LOCK") - { - // cursor is in the newly opened second pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn scrolling_inside_a_pane_with_mouse() { - 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); - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - 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.status_bar_appears() - && remote_terminal.snapshot_contains("LOCK") - { - remote_terminal.load_fixture("e2e/scrolling_inside_a_pane"); - 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(63, 21) - && remote_terminal.snapshot_contains("line21") - { - // all lines have been written to the pane - remote_terminal.send_key(&sgr_mouse_report(Position::new(2, 64), 64)); - 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; - if remote_terminal.cursor_position_is(63, 21) - && remote_terminal.snapshot_contains("line1 ") - && remote_terminal.snapshot_contains("SCROLL: 3/3") - && remote_terminal.snapshot_contains("LOCK") - { - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn start_without_pane_frames() { - 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); - let mut runner = RemoteRunner::new_without_frames(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(2, 1) - { - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - step_is_complete = true; - } - step_is_complete - }, - }); - 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; - if remote_terminal.cursor_position_is(62, 1) && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn mirrored_sessions() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let session_name = "mirrored_sessions"; - let (first_runner_snapshot, second_runner_snapshot) = loop { - // here we connect with one runner, then connect with another, perform some actions and - // then make sure they were also reflected (mirrored) in the first runner afterwards - RemoteRunner::kill_running_sessions(fake_win_size); - let mut first_runner = - RemoteRunner::new_with_session_name(fake_win_size, session_name, true) - .dont_panic() - .add_step(Step { - name: "Wait for app to load", - 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) - { - step_is_complete = true; - } - step_is_complete - }, - }); - first_runner.run_all_steps(); - - let mut second_runner = RemoteRunner::new_existing_session(fake_win_size, session_name) - .dont_panic() - .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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Open new tab (second user)", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) - && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Wait for new tab to open", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("Tab #2") - && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second tab - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Switch to previous tab", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #2") - { - // cursor is in the newly opened second pane - remote_terminal.send_key("some text".as_bytes()); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Wait for text to appear on screen", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("some text") { - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&MOVE_FOCUS_LEFT_IN_PANE_MODE); // same key as tab mode - step_is_complete = true; - } - step_is_complete - }, - }); - second_runner.run_all_steps(); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } - let second_runner_snapshot = second_runner.take_snapshot_after(Step { - name: "take snapshot after", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) - && remote_terminal.snapshot_contains("┐┌") - { - // cursor is back in the first tab - step_is_complete = true; - } - step_is_complete - }, - }); - let first_runner_snapshot = first_runner.take_snapshot_after(Step { - name: "take snapshot after", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) - && remote_terminal.snapshot_contains("┐┌") - { - // cursor is back in the first tab - step_is_complete = true; - } - step_is_complete - }, - }); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } else { - break (first_runner_snapshot, second_runner_snapshot); - } - }; - let first_runner_snapshot = account_for_races_in_snapshot(first_runner_snapshot); - let second_runner_snapshot = account_for_races_in_snapshot(second_runner_snapshot); - assert_snapshot!(first_runner_snapshot); - assert_snapshot!(second_runner_snapshot); -} - -#[test] -#[ignore] -pub fn multiple_users_in_same_pane_and_tab() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let session_name = "multiple_users_in_same_pane_and_tab"; - let (first_runner_snapshot, second_runner_snapshot) = loop { - // here we connect with one runner, then connect with another, perform some actions and - // then make sure they were also reflected (mirrored) in the first runner afterwards - RemoteRunner::kill_running_sessions(fake_win_size); - let mut first_runner = - RemoteRunner::new_with_session_name(fake_win_size, session_name, false) - .dont_panic() - .add_step(Step { - name: "Wait for app to load", - 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) - { - step_is_complete = true; - } - step_is_complete - }, - }); - first_runner.run_all_steps(); - - let mut second_runner = RemoteRunner::new_existing_session(fake_win_size, session_name) - .dont_panic() - .add_step(Step { - name: "Wait for app to load", - 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) - { - step_is_complete = true; - } - step_is_complete - }, - }); - second_runner.run_all_steps(); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } - let second_runner_snapshot = second_runner.take_snapshot_after(Step { - name: "take snapshot after", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("MY FOCUS") - { - // cursor is back in the first tab - step_is_complete = true; - } - step_is_complete - }, - }); - let first_runner_snapshot = first_runner.take_snapshot_after(Step { - name: "take snapshot after", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("MY FOCUS") - { - // cursor is back in the first tab - step_is_complete = true; - } - step_is_complete - }, - }); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } else { - break (first_runner_snapshot, second_runner_snapshot); - } - }; - let first_runner_snapshot = account_for_races_in_snapshot(first_runner_snapshot); - let second_runner_snapshot = account_for_races_in_snapshot(second_runner_snapshot); - assert_snapshot!(first_runner_snapshot); - assert_snapshot!(second_runner_snapshot); -} - -#[test] -#[ignore] -pub fn multiple_users_in_different_panes_and_same_tab() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let session_name = "multiple_users_in_same_pane_and_tab"; - let (first_runner_snapshot, second_runner_snapshot) = loop { - // here we connect with one runner, then connect with another, perform some actions and - // then make sure they were also reflected (mirrored) in the first runner afterwards - RemoteRunner::kill_running_sessions(fake_win_size); - let mut first_runner = - RemoteRunner::new_with_session_name(fake_win_size, session_name, false) - .dont_panic() - .add_step(Step { - name: "Wait for app to load", - 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) - { - step_is_complete = true; - } - step_is_complete - }, - }); - first_runner.run_all_steps(); - - let mut second_runner = RemoteRunner::new_existing_session(fake_win_size, session_name) - .dont_panic() - .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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - step_is_complete = true; - } - step_is_complete - }, - }); - second_runner.run_all_steps(); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } - - let second_runner_snapshot = second_runner.take_snapshot_after(Step { - name: "take snapshot after", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(63, 2) - && remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("LOCK") - { - // cursor is in the newly opened second pane - step_is_complete = true; - } - step_is_complete - }, - }); - - let first_runner_snapshot = first_runner.take_snapshot_after(Step { - name: "take snapshot after", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("││$") - && remote_terminal.tab_bar_appears() - { - // cursor is back in the first tab - step_is_complete = true; - } - step_is_complete - }, - }); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } else { - break (first_runner_snapshot, second_runner_snapshot); - } - }; - let first_runner_snapshot = account_for_races_in_snapshot(first_runner_snapshot); - let second_runner_snapshot = account_for_races_in_snapshot(second_runner_snapshot); - assert_snapshot!(first_runner_snapshot); - assert_snapshot!(second_runner_snapshot); -} - -#[test] -#[ignore] -pub fn multiple_users_in_different_tabs() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let session_name = "multiple_users_in_different_tabs"; - let (first_runner_snapshot, second_runner_snapshot) = loop { - // here we connect with one runner, then connect with another, perform some actions and - // then make sure they were also reflected (mirrored) in the first runner afterwards - RemoteRunner::kill_running_sessions(fake_win_size); - let mut first_runner = - RemoteRunner::new_with_session_name(fake_win_size, session_name, false) - .dont_panic() - .add_step(Step { - name: "Wait for app to load", - 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) - { - step_is_complete = true; - } - step_is_complete - }, - }); - first_runner.run_all_steps(); - - let mut second_runner = RemoteRunner::new_existing_session(fake_win_size, session_name) - .dont_panic() - .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(3, 2) - && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second pane - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - step_is_complete = true; - } - step_is_complete - }, - }); - second_runner.run_all_steps(); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } - - let second_runner_snapshot = second_runner.take_snapshot_after(Step { - name: "Wait for new tab to open", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("Tab #1 [ ]") - && remote_terminal.snapshot_contains("Tab #2") - && remote_terminal.status_bar_appears() - && !remote_terminal.snapshot_contains("AND:") - { - // cursor is in the newly opened second tab - step_is_complete = true; - } - step_is_complete - }, - }); - - let first_runner_snapshot = first_runner.take_snapshot_after(Step { - name: "Wait for new tab to open", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) - && remote_terminal.snapshot_contains("Tab #2 [ ]") - && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second tab - step_is_complete = true; - } - step_is_complete - }, - }); - - if (first_runner.test_timed_out || second_runner.test_timed_out) && test_attempts >= 0 { - test_attempts -= 1; - continue; - } else { - break (first_runner_snapshot, second_runner_snapshot); - } - }; - let first_runner_snapshot = account_for_races_in_snapshot(first_runner_snapshot); - let second_runner_snapshot = account_for_races_in_snapshot(second_runner_snapshot); - assert_snapshot!(first_runner_snapshot); - assert_snapshot!(second_runner_snapshot); -} - -#[test] -#[ignore] -pub fn bracketed_paste() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - // here we enter some text, before which we invoke "bracketed paste mode" - // we make sure the text in bracketed paste mode is sent directly to the terminal and not - // interpreted by us (in this case it will send ^T to the terminal), then we exit bracketed - // paste, send some more text and make sure it's also sent to the terminal - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { - name: "Send pasted text followed by normal text", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() - && remote_terminal.tab_bar_appears() - && remote_terminal.cursor_position_is(3, 2) - { - remote_terminal.send_key(&BRACKETED_PASTE_START); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key("a".as_bytes()); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key("b".as_bytes()); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key("c".as_bytes()); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&BRACKETED_PASTE_END); - 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; - if remote_terminal.snapshot_contains("abc") { - // text has been entered into the only terminal pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn toggle_floating_panes() { - 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); - let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { - name: "Toggle floating panes", - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&TOGGLE_FLOATING_PANES); - // back to normal mode after split - step_is_complete = true; - } - step_is_complete - }, - }); - 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; - if remote_terminal.cursor_position_is(33, 8) - && remote_terminal.snapshot_contains("STAGGERED") - && remote_terminal.snapshot_contains("LOCK") - { - // cursor is in the newly opened second pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn tmux_mode() { - 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); - 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(&TMUX_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_TMUX_MODE); - // back to normal mode after split - step_is_complete = true; - } - step_is_complete - }, - }); - 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; - if remote_terminal.cursor_position_is(63, 2) && remote_terminal.status_bar_appears() - { - // cursor is in the newly opened second pane - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn edit_scrollback() { - 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); - 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(&SCROLL_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&EDIT_SCROLLBACK); - step_is_complete = true; - } - step_is_complete - }, - }); - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for editor to appear", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains(".dump") { - // the .dump is an indication we get on the bottom line of vi when editing a - // file - // the temp file name is randomly generated, so we don't assert the whole snapshot - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - assert!(last_snapshot.contains(".dump")); -} - -#[test] -#[ignore] -pub fn undo_rename_tab() { - 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); - let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { - name: "Undo tab name change", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #1") - { - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&RENAME_TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&[97, 97]); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&ESC); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&ESC); - step_is_complete = true; - } - step_is_complete - }, - }); - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for tab name to apper on screen", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Tab #1") - && remote_terminal.snapshot_contains("LOCK") - { - step_is_complete = true - } - step_is_complete - }, - }); - - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn undo_rename_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); - let mut runner = RemoteRunner::new(fake_win_size).add_step(Step { - name: "Undo pane name change", - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&RENAME_PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&[97, 97]); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&ESC); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&ESC); - step_is_complete = true; - } - step_is_complete - }, - }); - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for pane name to apper on screen", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Pane #1") - && remote_terminal.snapshot_contains("LOCK") - { - step_is_complete = true - } - step_is_complete - }, - }); - - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn send_command_through_the_cli() { - // here we test the following flow: - // - send a command through the cli to run a bash script in a temporary folder - // - have it open a "command pane" that can be re-run with Enter - // - press Enter in the command pane to re-run the script - // - // the script appends the word "foo" to a temporary file and then `cat`s that file, - // so when we press "Enter", it will run again and we'll see two "foo"s one after the other, - // that's how we know the whole flow is working - let fake_win_size = Size { - cols: 150, - rows: 24, - }; - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new(fake_win_size) - .add_step(Step { - name: "Run command through the cli", - 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) - { - let fixture_folder = remote_terminal.path_to_fixture_folder(); - remote_terminal.send_command_through_the_cli(&format!( - "{}/append-echo-script.sh", - fixture_folder - )); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&ENTER); - std::thread::sleep(std::time::Duration::from_millis(100)); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Initial run of suspended command", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("<Ctrl-c>") { - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPACE); // run script - here we use SPACE - // instead of the default ENTER because - // sending ENTER over SSH can be a little - // problematic (read: I couldn't get it - // to pass consistently) - step_is_complete = true - } - step_is_complete - }, - }) - .add_step(Step { - name: "Wait for command to run", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("<Ctrl-c>") - && remote_terminal.cursor_position_is(76, 3) - { - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPACE); // re-run script - here we use SPACE - // instead of the default ENTER because - // sending ENTER over SSH can be a little - // problematic (read: I couldn't get it - // to pass consistently) - step_is_complete = true - } - step_is_complete - }, - }) - .add_step(Step { - name: "Wait for script to run again", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("<Ctrl-c>") - && remote_terminal.cursor_position_is(76, 4) - { - step_is_complete = true - } - step_is_complete - }, - }); - runner.run_all_steps(); - - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for script to run twice", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("foo") - && remote_terminal.cursor_position_is(76, 4) - { - step_is_complete = true - } - step_is_complete - }, - }); - - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] pub fn send_blocking_command_through_the_cli() { // here we test the following flow: // - send a blocking command through the cli with --blocking --floating --close-on-exit @@ -2499,456 +435,3 @@ pub fn send_blocking_command_through_the_cli() { let last_snapshot = account_for_races_in_snapshot(last_snapshot); assert_snapshot!(last_snapshot); } - -#[test] -#[ignore] -pub fn load_plugins_in_background_on_startup() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let config_file_name = "load_background_plugins.kdl"; - let mut test_attempts = 10; - let mut test_timed_out = false; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = - RemoteRunner::new_with_config(fake_win_size, config_file_name).add_step(Step { - name: "Wait for plugin to load and request permissions", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Allow? (y/n)") { - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key("y".as_bytes()); - step_is_complete = true; - } - step_is_complete - }, - }); - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for plugin to disappear after permissions were granted", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if !remote_terminal.snapshot_contains("Allow? (y/n)") { - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - test_timed_out = runner.test_timed_out; - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert!( - !test_timed_out, - "Test timed out, possibly waiting for permission request" - ); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn pin_floating_panes() { - 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); - let mut runner = RemoteRunner::new(fake_win_size) - .add_step(Step { - name: "Toggle floating panes", - 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); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&TOGGLE_FLOATING_PANES); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Pin floating pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("PIN [ ]") { - remote_terminal.send_key(&sgr_mouse_report(Position::new(8, 87), 0)); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Focus underlying pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("PIN [+]") { - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&TOGGLE_FLOATING_PANES); - std::thread::sleep(std::time::Duration::from_millis(100)); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Fill tiled pane with text", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.cursor_position_is(3, 2) { - remote_terminal.load_fixture("e2e/fill_for_pinned_pane"); - step_is_complete = true; - } - step_is_complete - }, - }) - .add_step(Step { - name: "Move cursor behind pinned pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.snapshot_contains("line") { - remote_terminal - .send_key(&format!(" hide_me").as_bytes().to_vec()); - step_is_complete = true; - } - step_is_complete - }, - }); - - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for cursor to be behind pinned pane", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if !remote_terminal.snapshot_contains("LOCK") { - remote_terminal.send_key(&PANE_MODE); - } - if remote_terminal.snapshot_contains("hide") - && remote_terminal.snapshot_contains("LOCK") - { - // terminal has been filled with fixture text - step_is_complete = true; - } - step_is_complete - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn watcher_client_functionality() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - let mut test_attempts = 10; - let session_name = "watcher_client_functionality"; - let (main_client_snapshot, watcher_snapshot) = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - - // Step 1: Create main client and wait for it to load - let mut main_client = - RemoteRunner::new_with_session_name(fake_win_size, session_name, false) - .retry_pause_ms(200) - .dont_panic() - .add_step(Step { - name: "Wait for app to load", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.cursor_position_is(3, 2) - }, - }); - main_client.run_all_steps(); - - // Step 2: Start a foreground process that produces periodic output and then - // replaces the shell with a long sleep. Using exec means pane 1 never returns - // to an interactive shell prompt, so a SIGWINCH on re-attach cannot trigger a - // prompt redraw — the snapshot is deterministic. - main_client = main_client.add_step(Step { - name: "Start foreground output loop", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - remote_terminal.send_key( - b"for i in 1 2 3; do sleep 1; echo WATCHER_OUTPUT_$i; done; echo WATCHER_DONE; exec sleep 1000000", - ); - remote_terminal.send_key(&ENTER); - true - }, - }); - main_client.run_all_steps(); - - // Step 3: Wait for first output line to appear - main_client = main_client.add_step(Step { - name: "Wait for first output", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let found = remote_terminal.snapshot_contains("WATCHER_OUTPUT_1"); - found - }, - }); - main_client.run_all_steps(); - - // Step 4: Attach watcher client - let mut watcher = RemoteRunner::new_watcher_session(fake_win_size, session_name) - .retry_pause_ms(200) - .dont_panic() - .add_step(Step { - name: "Wait for watcher to connect", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - // && remote_terminal.cursor_position_is(3, 2) - }, - }); - watcher.run_all_steps(); - - // Step 5: Main client splits pane right - main_client = main_client.add_step(Step { - name: "Split pane to the right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - if remote_terminal.status_bar_appears() { - remote_terminal.send_key(&PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - true - } else { - false - } - }, - }); - main_client.run_all_steps(); - - // Step 6: Verify watcher sees the split pane - watcher = watcher.add_step(Step { - name: "Watcher sees split pane", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() && remote_terminal.snapshot_contains("┐┌") - // vertical split indicator - }, - }); - watcher.run_all_steps(); - - // Step 7: Watcher tries to open a new tab (should be ignored) - watcher = watcher.add_step(Step { - name: "Watcher attempts to open new tab", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(500)); - remote_terminal.send_key(b"some text that should not appear..."); - std::thread::sleep(std::time::Duration::from_millis(500)); - true - }, - }); - watcher.run_all_steps(); - - // Step 8: Verify main client didn't receive the tab command - main_client = main_client.add_step(Step { - name: "Verify no new tab was created", - instruction: |remote_terminal: RemoteTerminal| -> bool { - // Should still be in Tab #1, not Tab #2 - remote_terminal.snapshot_contains("Tab #1") - && !remote_terminal.snapshot_contains("Tab #2") - }, - }); - main_client.run_all_steps(); - - // Step 9: Watcher sends mouse click (should be ignored) - watcher = watcher.add_step(Step { - name: "Watcher attempts mouse click", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let click_position = Position { - line: Line(10), - column: Column(10), - }; - remote_terminal.send_key(&sgr_mouse_report(click_position, 0)); // left click - std::thread::sleep(std::time::Duration::from_millis(500)); - true - }, - }); - watcher.run_all_steps(); - - // Step 10: Main client detaches - main_client = main_client.add_step(Step { - name: "Main client detaches", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - remote_terminal.send_key(&SESSION_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&DETACH_IN_SESSION_MODE); - true - }, - }); - main_client.run_all_steps(); - - // Step 11: Verify watcher receives output even with no main client - watcher = watcher.add_step(Step { - name: "Watcher sees WATCHER_OUTPUT_2", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.snapshot_contains("WATCHER_OUTPUT_2") - }, - }); - watcher.run_all_steps(); - - watcher = watcher.add_step(Step { - name: "Watcher sees WATCHER_OUTPUT_3", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.snapshot_contains("WATCHER_OUTPUT_3") - }, - }); - watcher.run_all_steps(); - - // Step 12: Main client re-attaches - let mut main_client_reattached = - RemoteRunner::new_existing_session(fake_win_size, session_name) - .dont_panic() - .add_step(Step { - name: "Main client re-attaches", - instruction: |remote_terminal: RemoteTerminal| -> bool { - std::thread::sleep(std::time::Duration::from_millis(500)); // wait for watcher - // to fail running - // commands - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("┐┌") - }, - }); - main_client_reattached.run_all_steps(); - - watcher.run_all_steps(); - - // Take final snapshots — WATCHER_DONE means the loop finished and pane 1 is now - // running `sleep 1000000` (via exec), so no interactive shell and no prompt redraws. - let main_client_snapshot = main_client_reattached.take_snapshot_after(Step { - name: "Take main client final snapshot", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("WATCHER_DONE") - && remote_terminal.snapshot_contains("┐┌") - }, - }); - - let watcher_snapshot = watcher.take_snapshot_after(Step { - name: "Take watcher final snapshot", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("WATCHER_DONE") - && remote_terminal.snapshot_contains("┐┌") - }, - }); - - if (main_client_reattached.test_timed_out || watcher.test_timed_out) && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break (main_client_snapshot, watcher_snapshot); - } - }; - - let main_client_snapshot = account_for_races_in_snapshot(main_client_snapshot); - let watcher_snapshot = account_for_races_in_snapshot(watcher_snapshot); - assert_snapshot!(main_client_snapshot); - assert_snapshot!(watcher_snapshot); -} - -#[test] -#[ignore] -pub fn override_layout_from_default_to_compact() { - 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); - - let mut runner = RemoteRunner::new(fake_win_size) - .add_step(Step { - name: "Wait for default layout to load", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - }, - }) - .add_step(Step { - name: "Override to compact layout", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - remote_terminal.run_zellij_action("override-layout compact"); - std::thread::sleep(std::time::Duration::from_millis(500)); - remote_terminal.send_key(&ENTER); - true - }, - }); - - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for compact layout to appear", - instruction: |remote_terminal: RemoteTerminal| -> bool { - // wait for both the layout indicator and the session name to render - remote_terminal.snapshot_contains("NORMAL") - && remote_terminal.snapshot_contains("e2e-test") - }, - }); - - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} - -#[test] -#[ignore] -pub fn use_custom_layout_with_relative_path() { - let fake_win_size = Size { - cols: 120, - rows: 24, - }; - // Should resolve to $fixtures/layouts/upside-down.kdl - let config_dir_name = "e2e-upside-down"; - let mut test_attempts = 10; - let last_snapshot = loop { - RemoteRunner::kill_running_sessions(fake_win_size); - let mut runner = RemoteRunner::new_with_config_dir(fake_win_size, config_dir_name); - runner.run_all_steps(); - let last_snapshot = runner.take_snapshot_after(Step { - name: "Wait for app to start", - instruction: |remote_terminal: RemoteTerminal| -> bool { - let lines = remote_terminal.lines(); - lines.len() > 2 - && lines[0].trim().starts_with("Ctrl +") - && lines[1].trim().starts_with("Tip:") - }, - }); - if runner.test_timed_out && test_attempts > 0 { - test_attempts -= 1; - continue; - } else { - break last_snapshot; - } - }; - let last_snapshot = account_for_races_in_snapshot(last_snapshot); - assert_snapshot!(last_snapshot); -} diff --git a/src/tests/e2e/mod.rs b/src/tests/e2e/mod.rs index 05f2cc8c..3cf63542 100644 --- a/src/tests/e2e/mod.rs +++ b/src/tests/e2e/mod.rs @@ -1,3 +1,2 @@ pub mod cases; mod remote_runner; -mod steps; diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index 958b8f1e..9f6eec44 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -12,15 +12,11 @@ use ssh2::Session; use std::io::prelude::*; use std::net::TcpStream; -use std::path::Path; - use std::cell::RefCell; use std::rc::Rc; const ZELLIJ_EXECUTABLE_LOCATION: &str = "/usr/src/zellij/zellij"; const SET_ENV_VARIABLES: &str = "EDITOR=/usr/bin/vi"; -const ZELLIJ_CONFIG_PATH: &str = "/usr/src/zellij/fixtures/configs"; -const ZELLIJ_CONFIG_DIRS_PATH: &str = "/usr/src/zellij/fixtures/config-dirs"; const ZELLIJ_DATA_DIR: &str = "/usr/src/zellij/e2e-data"; const ZELLIJ_FIXTURE_PATH: &str = "/usr/src/zellij/fixtures"; const CONNECTION_STRING: &str = "127.0.0.1:2222"; @@ -40,16 +36,6 @@ fn ssh_connect() -> ssh2::Session { sess } -fn ssh_connect_without_timeout() -> ssh2::Session { - let tcp = TcpStream::connect(CONNECTION_STRING).unwrap(); - let mut sess = Session::new().unwrap(); - sess.set_tcp_stream(tcp); - sess.handshake().unwrap(); - sess.userauth_password(CONNECTION_USERNAME, CONNECTION_PASSWORD) - .unwrap(); - sess -} - fn setup_remote_environment(channel: &mut ssh2::Channel, win_size: Size) { let (columns, rows) = (win_size.cols as u32, win_size.rows as u32); channel @@ -99,34 +85,6 @@ fn start_zellij(channel: &mut ssh2::Channel) { channel.flush().unwrap(); } -fn start_zellij_with_config_dir(channel: &mut ssh2::Channel, config_dir: &str) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --session {} --data-dir {} --config-dir {} options --show-release-notes false --show-startup-tips false\n", - SET_ENV_VARIABLES, ZELLIJ_EXECUTABLE_LOCATION, SESSION_NAME, ZELLIJ_DATA_DIR, format!("{}/{}", ZELLIJ_CONFIG_DIRS_PATH, config_dir) - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - -fn start_zellij_mirrored_session(channel: &mut ssh2::Channel) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --session {} --data-dir {} options --show-release-notes false --show-startup-tips false --mirror-session true --serialization-interval 1\n", - SET_ENV_VARIABLES, ZELLIJ_EXECUTABLE_LOCATION, SESSION_NAME, ZELLIJ_DATA_DIR - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - fn start_zellij_mirrored_session_with_layout(channel: &mut ssh2::Channel, layout_file_name: &str) { stop_zellij(channel); channel @@ -145,103 +103,6 @@ fn start_zellij_mirrored_session_with_layout(channel: &mut ssh2::Channel, layout channel.flush().unwrap(); } -fn start_zellij_mirrored_session_with_layout_and_viewport_serialization( - channel: &mut ssh2::Channel, - layout_file_name: &str, -) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --session {} --data-dir {} --new-session-with-layout {} options --show-release-notes false --show-startup-tips false --mirror-session true --serialize-pane-viewport true --serialization-interval 1\n", - SET_ENV_VARIABLES, - ZELLIJ_EXECUTABLE_LOCATION, - SESSION_NAME, - ZELLIJ_DATA_DIR, - format!("{}/{}", ZELLIJ_FIXTURE_PATH, layout_file_name) - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - -fn start_zellij_in_session(channel: &mut ssh2::Channel, session_name: &str, mirrored: bool) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --session {} --data-dir {} options --show-release-notes false --show-startup-tips false --mirror-session {}\n", - SET_ENV_VARIABLES, - ZELLIJ_EXECUTABLE_LOCATION, - session_name, - ZELLIJ_DATA_DIR, - mirrored - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - -fn attach_to_existing_session(channel: &mut ssh2::Channel, session_name: &str) { - channel - .write_all( - format!( - "{} {} attach {}\n", - SET_ENV_VARIABLES, ZELLIJ_EXECUTABLE_LOCATION, session_name - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - -fn watch_existing_session(channel: &mut ssh2::Channel, session_name: &str) { - channel - .write_all( - format!( - "{} {} watch {}\n", - SET_ENV_VARIABLES, ZELLIJ_EXECUTABLE_LOCATION, session_name - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - -fn start_zellij_without_frames(channel: &mut ssh2::Channel) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --session {} --data-dir {} options --show-release-notes false --show-startup-tips false --pane-frames false\n", - SET_ENV_VARIABLES, ZELLIJ_EXECUTABLE_LOCATION, SESSION_NAME, ZELLIJ_DATA_DIR - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - -fn start_zellij_with_config(channel: &mut ssh2::Channel, config_path: &str) { - stop_zellij(channel); - channel - .write_all( - format!( - "{} {} --config {} --session {} --data-dir {} options --show-release-notes false --show-startup-tips false\n", - SET_ENV_VARIABLES, - ZELLIJ_EXECUTABLE_LOCATION, - config_path, - SESSION_NAME, - ZELLIJ_DATA_DIR - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); -} - fn wait_for_startup(last_snapshot: &Arc<Mutex<String>>) { let start = std::time::Instant::now(); let timeout = std::time::Duration::from_secs(10); @@ -441,10 +302,6 @@ impl RemoteTerminal { pub fn snapshot_contains(&self, text: &str) -> bool { self.last_snapshot.lock().unwrap().contains(text) } - pub fn lines(&self) -> Vec<String> { - let s = self.last_snapshot.lock().unwrap(); - s.lines().map(|s| s.to_owned()).collect::<Vec<_>>() - } #[allow(unused)] pub fn current_snapshot(&self) -> String { // convenience method for writing tests, @@ -483,29 +340,6 @@ impl RemoteTerminal { } // release mutex before sleeping so the reader thread can process Zellij's startup output std::thread::sleep(std::time::Duration::from_secs(1)); // wait until Zellij stops parsing startup ANSI codes from the terminal STDIN } - pub fn run_zellij_action(&mut self, action_and_arguments: &str) { - let mut channel = self.channel.lock().unwrap(); - channel - .write_all( - format!( - "{} action {}", - ZELLIJ_EXECUTABLE_LOCATION, action_and_arguments - ) - .as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); - } - pub fn send_command_through_the_cli(&mut self, command: &str) { - let mut channel = self.channel.lock().unwrap(); - channel - .write_all( - // note that this is run with the -s flag that suspends the command on startup - format!("{} run -s -- \"{}\"", ZELLIJ_EXECUTABLE_LOCATION, command).as_bytes(), - ) - .unwrap(); - channel.flush().unwrap(); - } pub fn send_blocking_command_through_the_cli(&mut self, command: &str) { let mut channel = self.channel.lock().unwrap(); channel @@ -519,16 +353,6 @@ impl RemoteTerminal { .unwrap(); channel.flush().unwrap(); } - pub fn path_to_fixture_folder(&self) -> String { - ZELLIJ_FIXTURE_PATH.to_string() - } - pub fn load_fixture(&mut self, name: &str) { - let mut channel = self.channel.lock().unwrap(); - channel - .write_all(format!("cat {ZELLIJ_FIXTURE_PATH}/{name}\n").as_bytes()) - .unwrap(); - channel.flush().unwrap(); - } } #[derive(Clone)] @@ -544,7 +368,6 @@ pub struct RemoteRunner { currently_running_step: Option<String>, retries_left: usize, retry_pause_ms: usize, - panic_on_no_retries_left: bool, last_snapshot: Arc<Mutex<String>>, cursor_coordinates: Arc<Mutex<(usize, usize)>>, // x, y reader_thread: (Arc<AtomicBool>, std::thread::JoinHandle<()>), @@ -585,85 +408,6 @@ impl RemoteRunner { retries_left: RETRIES, retry_pause_ms: 100, test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_with_config_dir(win_size: Size, config_dir_name: &str) -> Self { - let sess = ssh_connect(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_with_config_dir(&mut channel, config_dir_name); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_mirrored_session(win_size: Size) -> Self { - let sess = ssh_connect(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_mirrored_session(&mut channel); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, last_snapshot, cursor_coordinates, reader_thread, @@ -702,52 +446,6 @@ impl RemoteRunner { retries_left: RETRIES, retry_pause_ms: 100, test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_mirrored_session_with_layout_and_viewport_serialization( - win_size: Size, - layout_file_name: &str, - ) -> Self { - let sess = ssh_connect(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_mirrored_session_with_layout_and_viewport_serialization( - &mut channel, - layout_file_name, - ); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, last_snapshot, cursor_coordinates, reader_thread, @@ -765,207 +463,6 @@ impl RemoteRunner { sess.set_blocking(false); wait_for_shell_output(&mut channel, CLEANUP_DONE_MARKER); } - pub fn new_with_session_name(win_size: Size, session_name: &str, mirrored: bool) -> Self { - // notice that this method does not have a timeout, so use with caution! - let sess = ssh_connect_without_timeout(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_in_session(&mut channel, session_name, mirrored); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_existing_session(win_size: Size, session_name: &str) -> Self { - let sess = ssh_connect_without_timeout(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - attach_to_existing_session(&mut channel, session_name); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_watcher_session(win_size: Size, session_name: &str) -> Self { - let sess = ssh_connect_without_timeout(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - watch_existing_session(&mut channel, session_name); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_without_frames(win_size: Size) -> Self { - let sess = ssh_connect(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_without_frames(&mut channel); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn new_with_config(win_size: Size, config_file_name: &'static str) -> Self { - let remote_path = Path::new(ZELLIJ_CONFIG_PATH).join(config_file_name); - let sess = ssh_connect(); - let mut channel = sess.channel_session().unwrap(); - let mut rows = Dimension::fixed(win_size.rows); - let mut cols = Dimension::fixed(win_size.cols); - rows.set_inner(win_size.rows); - cols.set_inner(win_size.cols); - let pane_geom = PaneGeom { - x: 0, - y: 0, - rows, - cols, - stacked: None, - is_pinned: false, - logical_position: None, - }; - setup_remote_environment(&mut channel, win_size); - start_zellij_with_config(&mut channel, &remote_path.to_string_lossy()); - let channel = Arc::new(Mutex::new(channel)); - let last_snapshot = Arc::new(Mutex::new(String::new())); - let cursor_coordinates = Arc::new(Mutex::new((0, 0))); - sess.set_blocking(false); - let reader_thread = - read_from_channel(&channel, &last_snapshot, &cursor_coordinates, &pane_geom); - wait_for_startup(&last_snapshot); - RemoteRunner { - steps: vec![], - channel, - currently_running_step: None, - current_step_index: 0, - retries_left: RETRIES, - retry_pause_ms: 100, - test_timed_out: false, - panic_on_no_retries_left: true, - last_snapshot, - cursor_coordinates, - reader_thread, - } - } - pub fn dont_panic(mut self) -> Self { - self.panic_on_no_retries_left = false; - self - } #[allow(unused)] pub fn retry_pause_ms(mut self, retry_pause_ms: usize) -> Self { self.retry_pause_ms = retry_pause_ms; diff --git a/src/tests/e2e/steps.rs b/src/tests/e2e/steps.rs deleted file mode 100644 index cc8b5c5d..00000000 --- a/src/tests/e2e/steps.rs +++ /dev/null @@ -1,152 +0,0 @@ -use super::cases::{ - MOVE_FOCUS_LEFT_IN_NORMAL_MODE, MOVE_TAB_LEFT, MOVE_TAB_RIGHT, NEW_TAB_IN_TAB_MODE, - SECOND_TAB_CONTENT, TAB_MODE, -}; -use super::remote_runner::{RemoteTerminal, Step}; - -pub fn new_tab() -> Step { - Step { - name: "Open new tab", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() { - remote_terminal.send_key(&TAB_MODE); - std::thread::sleep(std::time::Duration::from_millis(100)); - remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); - step_is_complete = true; - } - step_is_complete - }, - } -} - -pub fn check_second_tab_opened() -> Step { - Step { - name: "Check second tab opened", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() && remote_terminal.snapshot_contains("Tab #2") - }, - } -} - -pub fn move_tab_left() -> Step { - Step { - name: "Move tab left", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() { - remote_terminal.send_key(&MOVE_TAB_LEFT); - std::thread::sleep(std::time::Duration::from_millis(100)); - step_is_complete = true; - } - step_is_complete - }, - } -} - -pub fn check_third_tab_moved_left() -> Step { - Step { - name: "Check third tab is in the middle", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #1 Tab #3 Tab #2") - }, - } -} - -pub fn type_second_tab_content() -> Step { - Step { - name: "Type second tab content", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - if remote_terminal.snapshot_contains("Tab #2 content") { - return true; - } - // send (or re-send if the previous attempt arrived garbled) and wait for the next - // retry to confirm the content appeared correctly in the terminal - if remote_terminal.status_bar_appears() { - remote_terminal.send_key(&SECOND_TAB_CONTENT); - // sleep longer than the reader's idle poll (100ms) so the snapshot is updated - // before the next retry fires, preventing a spurious re-send - std::thread::sleep(std::time::Duration::from_millis(300)); - } - false - }, - } -} - -pub fn check_third_tab_opened() -> Step { - Step { - name: "Check third tab opened", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() && remote_terminal.snapshot_contains("Tab #3") - }, - } -} - -pub fn switch_focus_to_left_tab() -> Step { - Step { - name: "Move focus to tab on the left", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() { - remote_terminal.send_key(&MOVE_FOCUS_LEFT_IN_NORMAL_MODE); - step_is_complete = true; - } - step_is_complete - }, - } -} - -pub fn check_focus_on_second_tab() -> Step { - Step { - name: "Check focus is on the second tab", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #2 content") - }, - } -} - -pub fn move_tab_right() -> Step { - Step { - name: "Move tab right", - instruction: |mut remote_terminal: RemoteTerminal| -> bool { - let mut step_is_complete = false; - if remote_terminal.status_bar_appears() { - remote_terminal.send_key(&MOVE_TAB_RIGHT); - step_is_complete = true; - } - step_is_complete - }, - } -} - -pub fn check_third_tab_moved_to_beginning() -> Step { - Step { - name: "Check third tab moved to beginning", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #3 Tab #1 Tab #2") - }, - } -} - -pub fn check_third_tab_is_left_wrapped() -> Step { - Step { - name: "Check third tab is in last position", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #2 Tab #1 Tab #3") - }, - } -} - -pub fn check_third_tab_is_right_wrapped() -> Step { - Step { - name: "Check third tab is in last position", - instruction: |remote_terminal: RemoteTerminal| -> bool { - remote_terminal.status_bar_appears() - && remote_terminal.snapshot_contains("Tab #3 Tab #2 Tab #1") - }, - } -} |
