From dd5ea26cc72f3c39e9f8b4d8452a42c9c2f85442 Mon Sep 17 00:00:00 2001 From: Bartosz Zbytniewski <50180524+devzbysiu@users.noreply.github.com> Date: Sun, 18 Feb 2024 19:40:03 +0100 Subject: feat: add moving tab to other position (#3047) * feat: add moving tab to other position * docs(changelog): revert changes * test: update config snapshots * refactor: get rid of HorizontalDirection enum * refactor: cleanup code order * refactor: use debug! instead of info! * refactor: use more defensive way to switch tabs * refactor: revert tip changes * refactor: code formatting * refactor: improve invalid input notification * refactor: inline fns for calculating target index --------- Co-authored-by: Jae-Heon Ji --- src/tests/e2e/cases.rs | 123 +++++++++++++++++ src/tests/e2e/mod.rs | 1 + ...ellij__tests__e2e__cases__move_tab_to_left.snap | 29 ++++ ...es__move_tab_to_left_until_it_wraps_around.snap | 28 ++++ ...llij__tests__e2e__cases__move_tab_to_right.snap | 29 ++++ ...s__move_tab_to_right_until_it_wraps_around.snap | 28 ++++ src/tests/e2e/steps.rs | 153 +++++++++++++++++++++ 7 files changed, 391 insertions(+) create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left.snap create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left_until_it_wraps_around.snap create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right.snap create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right_until_it_wraps_around.snap create mode 100644 src/tests/e2e/steps.rs (limited to 'src/tests/e2e') diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index be337ea92..f2dd09332 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -9,6 +9,13 @@ 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 @@ -56,6 +63,9 @@ pub const SWITCH_PREV_TAB_IN_TAB_MODE: [u8; 1] = [104]; // h pub const CLOSE_TAB_IN_TAB_MODE: [u8; 1] = [120]; // x pub const RENAME_TAB_MODE: [u8; 1] = [114]; // r +pub const MOVE_TAB_LEFT: [u8; 2] = [27, 105]; // Alt + i +pub const MOVE_TAB_RIGHT: [u8; 2] = [27, 111]; // Alt + o + pub const SESSION_MODE: [u8; 1] = [15]; // ctrl-o pub const DETACH_IN_SESSION_MODE: [u8; 1] = [100]; // d @@ -63,6 +73,9 @@ pub const BRACKETED_PASTE_START: [u8; 6] = [27, 91, 50, 48, 48, 126]; // \u{1b}[ pub const BRACKETED_PASTE_END: [u8; 6] = [27, 91, 50, 48, 49, 126]; // \u{1b}[201 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 { // button: (release is with lower case m, not supported here yet) // 0 => left click @@ -511,6 +524,116 @@ pub fn close_tab() { 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() { diff --git a/src/tests/e2e/mod.rs b/src/tests/e2e/mod.rs index 3cf635425..05f2cc8cd 100644 --- a/src/tests/e2e/mod.rs +++ b/src/tests/e2e/mod.rs @@ -1,2 +1,3 @@ pub mod cases; mod remote_runner; +mod steps; diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left.snap new file mode 100644 index 000000000..2e3add784 --- /dev/null +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left.snap @@ -0,0 +1,29 @@ +--- +source: src/tests/e2e/cases.rs +assertion_line: 531 +expression: account_for_races_in_snapshot(last_snapshot) +--- + Zellij (e2e-test)  Tab #1  Tab #3  Tab #2  +┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│$ █ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left_until_it_wraps_around.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left_until_it_wraps_around.snap new file mode 100644 index 000000000..9479e355c --- /dev/null +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_left_until_it_wraps_around.snap @@ -0,0 +1,28 @@ +--- +source: src/tests/e2e/cases.rs +expression: account_for_races_in_snapshot(last_snapshot) +--- + Zellij (e2e-test)  Tab #2  Tab #1  Tab #3  +┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│$ █ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right.snap new file mode 100644 index 000000000..2aee51c51 --- /dev/null +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right.snap @@ -0,0 +1,29 @@ +--- +source: src/tests/e2e/cases.rs +assertion_line: 624 +expression: account_for_races_in_snapshot(last_snapshot) +--- + Zellij (e2e-test)  Tab #1  Tab #3  Tab #2  +┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│$ Tab #2 content█ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right_until_it_wraps_around.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right_until_it_wraps_around.snap new file mode 100644 index 000000000..9c2303a56 --- /dev/null +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__move_tab_to_right_until_it_wraps_around.snap @@ -0,0 +1,28 @@ +--- +source: src/tests/e2e/cases.rs +expression: account_for_races_in_snapshot(last_snapshot) +--- + Zellij (e2e-test)  Tab #3  Tab #2  Tab #1  +┌ Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│$ █ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  + Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/steps.rs b/src/tests/e2e/steps.rs new file mode 100644 index 000000000..c09fc9392 --- /dev/null +++ b/src/tests/e2e/steps.rs @@ -0,0 +1,153 @@ +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.tip_appears() && remote_terminal.status_bar_appears() { + remote_terminal.send_key(&TAB_MODE); + 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.tip_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.tip_appears() && remote_terminal.status_bar_appears() { + remote_terminal.send_key(&MOVE_TAB_LEFT); + 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.tip_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 { + let mut step_is_complete = false; + if remote_terminal.tip_appears() && remote_terminal.status_bar_appears() { + remote_terminal.send_key(&SECOND_TAB_CONTENT); + step_is_complete = true; + } + step_is_complete + }, + } +} + +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.tip_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.tip_appears() && 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.tip_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.tip_appears() && 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.tip_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.tip_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.tip_appears() + && remote_terminal.snapshot_contains("Tab #3  Tab #2  Tab #1") + }, + } +} -- cgit v1.2.3