aboutsummaryrefslogtreecommitdiff
path: root/src/client/shell/tests
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-09-09 23:56:53 +0300
committerGitHub <noreply@github.com>2026-09-09 23:56:53 +0300
commit120c682008a85dc17d7a13cc619a2fd5d25f3924 (patch)
tree0119dfbe37bba91053f985ba60f3ee399d2ea797 /src/client/shell/tests
parent985d3442b4b8a6f2e25a62821aab58d63d8ce2cf (diff)
fix: restore connected session navigator tree glyphs (#3861)
refs #3843 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Diffstat (limited to 'src/client/shell/tests')
-rw-r--r--src/client/shell/tests/copy.rs137
-rw-r--r--src/client/shell/tests/endpoints.rs16
2 files changed, 153 insertions, 0 deletions
diff --git a/src/client/shell/tests/copy.rs b/src/client/shell/tests/copy.rs
index 95413f8a..fa0635af 100644
--- a/src/client/shell/tests/copy.rs
+++ b/src/client/shell/tests/copy.rs
@@ -732,6 +732,143 @@ fn copy_search_owns_prompt_repeat_highlights_selection_and_restore() {
}
#[test]
+fn navigator_renders_connected_siblings_and_ancestor_lines() {
+ let mut snapshot = snapshot();
+ snapshot.focused_pane_id = None;
+ snapshot.tabs[0].label = "editor".into();
+ snapshot.panes[0].label = Some("agent".into());
+ snapshot.panes[0].focused = false;
+ let mut shell = snapshot.panes[0].clone();
+ shell.pane_id = "pane_shell".into();
+ shell.label = Some("shell".into());
+ snapshot.panes.push(shell);
+ for label in ["notes", "logs"] {
+ let mut tab = snapshot.tabs[0].clone();
+ tab.tab_id = format!("tab_{label}");
+ tab.label = label.into();
+ tab.focused = false;
+ tab.number = snapshot.tabs.len() + 1;
+ let mut pane = snapshot.panes[0].clone();
+ pane.pane_id = format!("pane_{label}");
+ pane.tab_id = tab.tab_id.clone();
+ pane.label = Some(label.into());
+ pane.focused = false;
+ snapshot.tabs.push(tab);
+ snapshot.panes.push(pane);
+ }
+ let mut workspace = snapshot.workspaces[0].clone();
+ workspace.workspace_id = "ws_2".into();
+ workspace.active_tab_id = "tab_last".into();
+ workspace.label = "second".into();
+ workspace.number = 2;
+ workspace.focused = false;
+ let mut tab = snapshot.tabs[0].clone();
+ tab.workspace_id = workspace.workspace_id.clone();
+ tab.tab_id = workspace.active_tab_id.clone();
+ tab.label = "last".into();
+ tab.focused = false;
+ let mut pane = snapshot.panes[0].clone();
+ pane.workspace_id = workspace.workspace_id.clone();
+ pane.tab_id = tab.tab_id.clone();
+ pane.pane_id = "pane_last".into();
+ snapshot.workspaces.push(workspace);
+ snapshot.tabs.push(tab);
+ snapshot.panes.push(pane);
+ let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default()));
+ state.set_snapshot(Box::new(snapshot));
+ state.set_pane_surface(surface());
+ state.open_navigator_overlay();
+ let prefixes = |state: &mut ClientShellState, height| {
+ let frame = state.compose(106, height).expect("navigator frame");
+ state
+ .hits
+ .navigator_rows
+ .iter()
+ .map(|(rect, _)| {
+ frame.cells[rect.y as usize * frame.width as usize + rect.x as usize + 1..]
+ .iter()
+ .take(6)
+ .map(|cell| cell.symbol.as_str())
+ .collect::<String>()
+ })
+ .collect::<Vec<_>>()
+ };
+ assert_eq!(
+ prefixes(&mut state, 30),
+ [
+ "▾ clie",
+ "├── ed",
+ "│ ├──",
+ "│ └──",
+ "├── no",
+ "│ └──",
+ "└── lo",
+ " └──",
+ "▾ seco",
+ "└── la",
+ " └──"
+ ]
+ );
+
+ // The editor ancestor is above this viewport; the logs sibling is below it.
+ let Some(ClientShellOverlay::Navigator(navigator)) = state.overlay.as_mut() else {
+ panic!("expected navigator");
+ };
+ navigator.scroll = 2;
+ navigator.selected = Some(ClientNavigatorTarget::Pane {
+ endpoint_id: state.active_endpoint_id.clone(),
+ pane_id: "pane_shell".into(),
+ });
+ assert_eq!(
+ prefixes(&mut state, 12),
+ ["│ ├──", "│ └──", "├── no", "│ └──"]
+ );
+
+ // Excluded siblings must not leave dangling continuation lines.
+ let Some(ClientShellOverlay::Navigator(navigator)) = state.overlay.as_mut() else {
+ panic!("expected navigator");
+ };
+ navigator.query = "shell".into();
+ navigator.scroll = 0;
+ assert_eq!(prefixes(&mut state, 30), ["▾ clie", "└── ed", " └──"]);
+ let Some(ClientShellOverlay::Navigator(navigator)) = state.overlay.as_mut() else {
+ panic!("expected navigator");
+ };
+ navigator.query.clear();
+ navigator.expanded_workspaces.clear();
+ assert_eq!(prefixes(&mut state, 30), ["▸ clie", "▸ seco"]);
+}
+
+#[test]
+#[ignore = "manual navigator composition scaling profile"]
+fn navigator_render_scale_profile() {
+ for panes in [1, 15, 52] {
+ let mut snapshot = snapshot();
+ for index in 1..panes {
+ let mut pane = snapshot.panes[0].clone();
+ pane.pane_id = format!("pane_{index}_extra");
+ pane.focused = false;
+ snapshot.panes.push(pane);
+ }
+ let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default()));
+ state.set_snapshot(Box::new(snapshot));
+ state.set_pane_surface(surface());
+ state.open_navigator_overlay();
+ for _ in 0..20 {
+ std::hint::black_box(state.compose(106, 30).expect("navigator frame"));
+ }
+ let start = std::time::Instant::now();
+ for _ in 0..1000 {
+ std::hint::black_box(state.compose(106, 30).expect("navigator frame"));
+ }
+ eprintln!(
+ "navigator: {panes} panes, {:.1} us/frame",
+ start.elapsed().as_secs_f64() * 1000.0
+ );
+ }
+}
+
+#[test]
fn navigator_owns_search_mouse_selection_and_stable_target_focus() {
let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default()));
state.set_snapshot(Box::new(snapshot()));
diff --git a/src/client/shell/tests/endpoints.rs b/src/client/shell/tests/endpoints.rs
index e425b794..0b69135e 100644
--- a/src/client/shell/tests/endpoints.rs
+++ b/src/client/shell/tests/endpoints.rs
@@ -1008,6 +1008,22 @@ fn navigator_uses_machine_parents_only_for_federated_clients() {
}));
assert_eq!(rows.iter().filter(|row| row.current).count(), 1);
+ let frame = state.compose(106, 30).expect("federated navigator");
+ for (rect, target) in &state.hits.navigator_rows {
+ let expected = match target {
+ ClientNavigatorTarget::Machine { .. } => " ▾ ",
+ ClientNavigatorTarget::Workspace { .. } => " ▾ ",
+ ClientNavigatorTarget::Tab { .. } => " └── ",
+ ClientNavigatorTarget::Pane { .. } => " └── ",
+ };
+ let prefix = frame.cells[rect.y as usize * frame.width as usize + rect.x as usize..]
+ .iter()
+ .take(expected.chars().count())
+ .map(|cell| cell.symbol.as_str())
+ .collect::<String>();
+ assert_eq!(prefix, expected, "{target:?}");
+ }
+
let mut local = ClientShellState::new(ClientShellConfig::from_config(&Config::default()));
local.set_snapshot(Box::new(snapshot()));
local.set_pane_surface(surface());