diff options
| author | Aram Drevekenin <aram@poor.dev> | 2026-06-25 17:09:26 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-25 17:09:26 +0200 |
| commit | 27291bea2893589b3274d5da7c81d80b3f487d26 (patch) | |
| tree | e71e46925f236b55ef73fd4f0ff7c6c3092eed32 /zellij-integration-tests/src | |
| parent | hotfix: fix flaky ci tests (diff) | |
| download | sl0ppij-27291bea2893589b3274d5da7c81d80b3f487d26.tar.gz sl0ppij-27291bea2893589b3274d5da7c81d80b3f487d26.tar.xz sl0ppij-27291bea2893589b3274d5da7c81d80b3f487d26.zip | |
tests: add more integration tests (#5308)
* test all the things
* consolidate shared harness
* rustfmt
Diffstat (limited to 'zellij-integration-tests/src')
| -rw-r--r-- | zellij-integration-tests/src/client_screen.rs | 28 | ||||
| -rw-r--r-- | zellij-integration-tests/src/harness.rs | 47 | ||||
| -rw-r--r-- | zellij-integration-tests/src/keys.rs | 62 | ||||
| -rw-r--r-- | zellij-integration-tests/src/lib.rs | 7 | ||||
| -rw-r--r-- | zellij-integration-tests/src/runner.rs | 18 |
5 files changed, 102 insertions, 60 deletions
diff --git a/zellij-integration-tests/src/client_screen.rs b/zellij-integration-tests/src/client_screen.rs index 3bddfa07..479c9b56 100644 --- a/zellij-integration-tests/src/client_screen.rs +++ b/zellij-integration-tests/src/client_screen.rs @@ -109,6 +109,26 @@ pub struct CursorPosition { pub y: usize, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Coord { + pub col: usize, + pub row: usize, +} + +pub fn col(col: usize) -> CoordBuilder { + CoordBuilder { col } +} + +pub struct CoordBuilder { + col: usize, +} + +impl CoordBuilder { + pub fn row(self, row: usize) -> Coord { + Coord { col: self.col, row } + } +} + #[derive(Clone, Debug)] pub struct GridSnapshot { pub text: String, @@ -119,8 +139,12 @@ impl GridSnapshot { pub fn contains(&self, needle: &str) -> bool { self.text.contains(needle) } - pub fn cursor_is_at(&self, x: usize, y: usize) -> bool { - self.cursor == Some(CursorPosition { x, y }) + pub fn cursor_is_at(&self, coord: Coord) -> bool { + self.cursor + == Some(CursorPosition { + x: coord.col, + y: coord.row, + }) } pub fn status_bar_appears(&self) -> bool { self.text.contains("Ctrl +") && self.text.contains("LOCK") diff --git a/zellij-integration-tests/src/harness.rs b/zellij-integration-tests/src/harness.rs new file mode 100644 index 00000000..eb860f8f --- /dev/null +++ b/zellij-integration-tests/src/harness.rs @@ -0,0 +1,47 @@ +use crate::{col, keys, FakePtyHandle, Size, TestRunner, TestSession}; + +pub const TERMINAL_SIZE: Size = Size { + cols: 120, + rows: 24, +}; +pub const PROMPT: &[u8] = b"$ "; + +pub fn start_zellij() -> TestSession { + TestRunner::new(TERMINAL_SIZE).start() +} + +pub fn claim_first_terminal_and_wait_for_prompt(zellij: &TestSession) -> FakePtyHandle { + let terminal = zellij.expect_pty_spawn(); + terminal.output(PROMPT); + zellij.wait_until( + "first terminal prompt rendered in loaded app", + |grid_snapshot| { + grid_snapshot.tab_bar_appears() + && grid_snapshot.status_bar_appears() + && grid_snapshot.cursor_is_at(col(3).row(2)) + }, + ); + terminal +} + +pub fn split_right_and_wait_for_prompt(zellij: &TestSession) -> FakePtyHandle { + zellij.send_stdin(&keys::ctrl('p')); + zellij.send_stdin(&keys::key('r')); + let terminal = zellij.expect_pty_spawn(); + terminal.output(PROMPT); + zellij.wait_until("right terminal prompt rendered", |grid_snapshot| { + grid_snapshot.status_bar_appears() && grid_snapshot.cursor_is_at(col(63).row(2)) + }); + terminal +} + +pub fn split_down_and_wait_for_prompt(zellij: &TestSession) -> FakePtyHandle { + zellij.send_stdin(&keys::ctrl('p')); + zellij.send_stdin(&keys::key('d')); + let terminal = zellij.expect_pty_spawn(); + terminal.output(PROMPT); + zellij.wait_until("lower terminal prompt rendered", |grid_snapshot| { + grid_snapshot.status_bar_appears() && grid_snapshot.cursor_is_at(col(3).row(13)) + }); + terminal +} diff --git a/zellij-integration-tests/src/keys.rs b/zellij-integration-tests/src/keys.rs index fe54b42d..e2cef994 100644 --- a/zellij-integration-tests/src/keys.rs +++ b/zellij-integration-tests/src/keys.rs @@ -1,63 +1,21 @@ const ESC_BYTE: u8 = 0x1b; -const fn ctrl(character: u8) -> [u8; 1] { - [character & 0x1f] +pub const fn ctrl(character: char) -> [u8; 1] { + [(character as u8) & 0x1f] } -const fn alt(character: u8) -> [u8; 2] { - [ESC_BYTE, character] +pub const fn alt(character: char) -> [u8; 2] { + [ESC_BYTE, character as u8] +} + +pub const fn key(character: char) -> [u8; 1] { + [character as u8] } -pub const QUIT: [u8; 1] = ctrl(b'q'); -pub const ESC: [u8; 1] = [ESC_BYTE]; pub const ENTER: [u8; 1] = [b'\r']; +pub const ESC: [u8; 1] = [ESC_BYTE]; pub const SPACE: [u8; 1] = [b' ']; -pub const LOCK_MODE: [u8; 1] = ctrl(b'g'); - -pub const MOVE_FOCUS_LEFT_IN_NORMAL_MODE: [u8; 2] = alt(b'h'); -pub const MOVE_FOCUS_RIGHT_IN_NORMAL_MODE: [u8; 2] = alt(b'l'); - -pub const PANE_MODE: [u8; 1] = ctrl(b'p'); -pub const TMUX_MODE: [u8; 1] = ctrl(b'b'); -pub const SPAWN_TERMINAL_IN_PANE_MODE: [u8; 1] = [b'n']; -pub const MOVE_FOCUS_IN_PANE_MODE: [u8; 1] = [b'p']; -pub const SPLIT_DOWN_IN_PANE_MODE: [u8; 1] = [b'd']; -pub const SPLIT_RIGHT_IN_PANE_MODE: [u8; 1] = [b'r']; -pub const SPLIT_RIGHT_IN_TMUX_MODE: [u8; 1] = [b'%']; -pub const TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE: [u8; 1] = [b'f']; -pub const TOGGLE_FLOATING_PANES: [u8; 1] = [b'w']; -pub const CLOSE_PANE_IN_PANE_MODE: [u8; 1] = [b'x']; -pub const MOVE_FOCUS_DOWN_IN_PANE_MODE: [u8; 1] = [b'j']; -pub const MOVE_FOCUS_UP_IN_PANE_MODE: [u8; 1] = [b'k']; -pub const MOVE_FOCUS_LEFT_IN_PANE_MODE: [u8; 1] = [b'h']; -pub const MOVE_FOCUS_RIGHT_IN_PANE_MODE: [u8; 1] = [b'l']; -pub const RENAME_PANE_MODE: [u8; 1] = [b'c']; - -pub const SCROLL_MODE: [u8; 1] = ctrl(b's'); -pub const SCROLL_UP_IN_SCROLL_MODE: [u8; 1] = [b'k']; -pub const SCROLL_DOWN_IN_SCROLL_MODE: [u8; 1] = [b'j']; -pub const SCROLL_PAGE_UP_IN_SCROLL_MODE: [u8; 1] = ctrl(b'b'); -pub const SCROLL_PAGE_DOWN_IN_SCROLL_MODE: [u8; 1] = ctrl(b'f'); -pub const EDIT_SCROLLBACK: [u8; 1] = [b'e']; - -pub const RESIZE_MODE: [u8; 1] = ctrl(b'n'); -pub const RESIZE_DOWN_IN_RESIZE_MODE: [u8; 1] = [b'j']; -pub const RESIZE_UP_IN_RESIZE_MODE: [u8; 1] = [b'k']; -pub const RESIZE_LEFT_IN_RESIZE_MODE: [u8; 1] = [b'h']; -pub const RESIZE_RIGHT_IN_RESIZE_MODE: [u8; 1] = [b'l']; - -pub const TAB_MODE: [u8; 1] = ctrl(b't'); -pub const NEW_TAB_IN_TAB_MODE: [u8; 1] = [b'n']; -pub const SWITCH_NEXT_TAB_IN_TAB_MODE: [u8; 1] = [b'l']; -pub const SWITCH_PREV_TAB_IN_TAB_MODE: [u8; 1] = [b'h']; -pub const CLOSE_TAB_IN_TAB_MODE: [u8; 1] = [b'x']; -pub const RENAME_TAB_MODE: [u8; 1] = [b'r']; - -pub const MOVE_TAB_LEFT: [u8; 2] = alt(b'i'); -pub const MOVE_TAB_RIGHT: [u8; 2] = alt(b'o'); - -pub const SESSION_MODE: [u8; 1] = ctrl(b'o'); -pub const DETACH_IN_SESSION_MODE: [u8; 1] = [b'd']; +pub const TAB: [u8; 1] = [b'\t']; pub const BRACKETED_PASTE_START: [u8; 6] = *b"\x1b[200~"; pub const BRACKETED_PASTE_END: [u8; 6] = *b"\x1b[201~"; diff --git a/zellij-integration-tests/src/lib.rs b/zellij-integration-tests/src/lib.rs index 15afe865..18f652fb 100644 --- a/zellij-integration-tests/src/lib.rs +++ b/zellij-integration-tests/src/lib.rs @@ -4,12 +4,17 @@ pub mod client_screen; pub mod fake_client_os_api; pub mod fake_pty; pub mod fake_server_os_api; +pub mod harness; pub mod keys; pub mod runner; pub mod test_env; -pub use client_screen::{ClientScreen, CursorPosition, GridSnapshot}; +pub use client_screen::{col, ClientScreen, Coord, CoordBuilder, CursorPosition, GridSnapshot}; pub use fake_pty::FakePtyHandle; +pub use harness::{ + claim_first_terminal_and_wait_for_prompt, split_down_and_wait_for_prompt, + split_right_and_wait_for_prompt, start_zellij, PROMPT, TERMINAL_SIZE, +}; pub use runner::{normalized, TestClient, TestRunner, TestSession}; pub use zellij_utils::data::LayoutInfo; pub use zellij_utils::pane_size::Size; diff --git a/zellij-integration-tests/src/runner.rs b/zellij-integration-tests/src/runner.rs index 26b59014..c430f94b 100644 --- a/zellij-integration-tests/src/runner.rs +++ b/zellij-integration-tests/src/runner.rs @@ -220,7 +220,7 @@ impl TestClient { } pub fn quit(mut self) { - self.send_stdin(&keys::QUIT); + self.send_stdin(&keys::ctrl('q')); self.join(); } @@ -477,8 +477,8 @@ impl TestSession { pub fn detach_main_client(&mut self) { let connected_clients_before_detach = self.fake_server_os_api.connected_client_count(); - self.send_stdin(&keys::SESSION_MODE); - self.send_stdin(&keys::DETACH_IN_SESSION_MODE); + self.send_stdin(&keys::ctrl('o')); + self.send_stdin(&keys::key('d')); self.main_client.join(); self.wait_for_server_to_release_a_client(connected_clients_before_detach); } @@ -498,7 +498,7 @@ impl TestSession { pub fn quit(&mut self) { if self.main_client.thread.is_some() { - self.send_stdin(&keys::QUIT); + self.send_stdin(&keys::ctrl('q')); self.main_client.join(); } if let Some(server_thread) = self.server_thread.lock().unwrap().take() { @@ -511,7 +511,7 @@ impl TestSession { .main_client .fake_client_handle .stdin_tx - .send(keys::QUIT.to_vec()); + .send(keys::ctrl('q').to_vec()); } } @@ -526,9 +526,17 @@ impl Drop for TestSession { pub fn normalized(grid_snapshot: &GridSnapshot) -> String { let text = replace_unique_session_name(&grid_snapshot.text); let text = strip_swap_layout_indication(&text); + let text = strip_tip_indication(&text); strip_trailing_whitespace(&text) } +fn strip_tip_indication(text: &str) -> String { + regex::Regex::new(r" Tip: [^\n]*") + .unwrap() + .replace_all(text, "") + .to_string() +} + fn replace_unique_session_name(text: &str) -> String { regex::Regex::new(r"Zellij \(test-\d+\)") .unwrap() |
