test(tui): add coverage for attention navigation + cross-session isolation
Some checks are pending
CI / rust (pull_request) Waiting to run
CI / markdown (pull_request) Waiting to run
CI / port (pull_request) Waiting to run
CI / agent-jail-pkgs (pull_request) Waiting to run

Four new tests closing the last attention-tier coverage gaps:

- jump_next_attention_skips_healthy_panes:
  Panes [ok, err, ok, stalled, ok] — proves n jumps 0→1→3→wrap→1,
  skipping healthy panes. Forward wrapping.

- jump_prev_attention_wraps_backwards:
  Same layout — proves N jumps 4→3→1→wrap→3.
  Backward wrapping.

- attention_bar_ignores_other_session_panes:
  Error pane in session s2, viewing session s1 — bar must NOT
  appear. Proves the filtered_panes()-based has_attention fix
  from commit 4d95f11.

- jump_next_attention_reports_when_no_attention_panes:
  All healthy panes — status message set to 'no attention',
  selection unchanged.

18 tests, workspace green (0 failures).
This commit is contained in:
123kupola 2026-06-25 21:18:36 +02:00
parent 4d95f1113f
commit de933fdf69

View file

@ -1165,4 +1165,175 @@ mod tests {
"should show normal header when no attention: {text}"
);
}
#[test]
fn jump_next_attention_skips_healthy_panes() {
// Panes: [ok, error, ok, stalled, ok]
// Attention at indices 1 (Error) and 3 (Stalled).
let snap = GlasspaneSnapshot::new(
"osa",
"2026-06-25T12:00:00Z",
vec![
colibri_glasspane::Pane {
id: "pane-0".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-1".into(), agent: "zot".into(),
state: AgentState::Error, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-2".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-3".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: true,
},
colibri_glasspane::Pane {
id: "pane-4".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
],
);
let mut app = App::new(PathBuf::from("/tmp/nonexistent.sock"));
app.snapshot = Some(snap);
// Start at index 0 → next attention is 1.
app.table_state.select(Some(0));
app.jump_next_attention();
assert_eq!(app.table_state.selected(), Some(1), "jump from 0 → 1");
// From 1 → next is 3.
app.jump_next_attention();
assert_eq!(app.table_state.selected(), Some(3), "jump from 1 → 3");
// From 3 → wrap to 1.
app.jump_next_attention();
assert_eq!(app.table_state.selected(), Some(1), "wrap 3 → 1");
}
#[test]
fn jump_prev_attention_wraps_backwards() {
// Same panes: attention at 1 and 3.
let snap = GlasspaneSnapshot::new(
"osa",
"2026-06-25T12:00:00Z",
vec![
colibri_glasspane::Pane {
id: "pane-0".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-1".into(), agent: "zot".into(),
state: AgentState::Error, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-2".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-3".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: true,
},
colibri_glasspane::Pane {
id: "pane-4".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
},
],
);
let mut app = App::new(PathBuf::from("/tmp/nonexistent.sock"));
app.snapshot = Some(snap);
// Start at index 4 → prev attention is 3.
app.table_state.select(Some(4));
app.jump_prev_attention();
assert_eq!(app.table_state.selected(), Some(3), "jump from 4 ← 3");
// From 3 → prev is 1.
app.jump_prev_attention();
assert_eq!(app.table_state.selected(), Some(1), "jump from 3 ← 1");
// From 1 → wrap to 3.
app.jump_prev_attention();
assert_eq!(app.table_state.selected(), Some(3), "wrap 1 ← 3");
}
#[test]
fn attention_bar_ignores_other_session_panes() {
// Error pane in session "s2", but we're viewing session "s1".
// The attention bar must NOT appear because filtered_panes()
// excludes s2 panes when session_filter = Some("s1").
let snap = GlasspaneSnapshot::new(
"osa",
"2026-06-25T12:00:00Z",
vec![
colibri_glasspane::Pane {
id: "pane-s1-ok".into(), agent: "zot".into(),
state: AgentState::Working,
session_id: Some("s1".into()),
last_event_at: None, cwd: None, stalled: false,
},
colibri_glasspane::Pane {
id: "pane-s2-err".into(), agent: "zot".into(),
state: AgentState::Error,
session_id: Some("s2".into()),
last_event_at: None, cwd: None, stalled: false,
},
],
);
let mut app = App::new(PathBuf::from("/tmp/nonexistent.sock"));
app.snapshot = Some(snap);
app.rebuild_session_list();
// Navigate to session s1 (rebuild selects first alphabetically = s1).
app.session_filter = Some("s1".into());
let text = render_text(&mut app, 80, 24);
assert!(
!text.contains("ATTENTION"),
"should not show attention bar for error in other session: {text}"
);
assert!(
text.contains("pane-s1-ok"),
"should show healthy pane from current session: {text}"
);
assert!(
!text.contains("pane-s2-err"),
"should not show pane from other session: {text}"
);
}
#[test]
fn jump_next_attention_reports_when_no_attention_panes() {
let snap = GlasspaneSnapshot::new(
"osa",
"2026-06-25T12:00:00Z",
vec![colibri_glasspane::Pane {
id: "pane-ok".into(), agent: "zot".into(),
state: AgentState::Working, session_id: None,
last_event_at: None, cwd: None, stalled: false,
}],
);
let mut app = App::new(PathBuf::from("/tmp/nonexistent.sock"));
app.snapshot = Some(snap);
app.table_state.select(Some(0));
app.jump_next_attention();
// Should not have moved.
assert_eq!(app.table_state.selected(), Some(0));
// Status message should be set.
assert!(app.status_msg.is_some());
let msg = &app.status_msg.as_ref().unwrap().0;
assert!(msg.contains("no attention"), "expected 'no attention' in: {msg}");
}
}