use super::super::*;
use super::support::*;
#[test]
fn alt_c_collapses_all_activity_tree_when_no_startup_prompt_is_queued() {
let mut state = state_with_parent_and_child();
state.expanded.insert(ActivityId::new("parent"));
assert_eq!(
handle_key(
modified_key(KeyCode::Char('c'), KeyModifiers::ALT),
&mut state,
),
InputAction::None
);
assert!(state.expanded.is_empty());
}
#[test]
fn modifier_bindings_trigger_activity_actions() {
let mut state = state_with_activity();
state.focus_activity_tree();
assert_eq!(state.selected, 0);
assert!(matches!(
handle_key(
modified_key(KeyCode::Char('j'), KeyModifiers::ALT),
&mut state
),
InputAction::None
));
assert_eq!(state.selected, 1);
assert!(matches!(
handle_key(
modified_key(KeyCode::Char('k'), KeyModifiers::ALT),
&mut state
),
InputAction::None
));
assert_eq!(state.selected, 0);
assert!(matches!(
handle_key(
modified_key(KeyCode::Char('f'), KeyModifiers::ALT),
&mut state
),
InputAction::None
));
assert_eq!(state.selected, 1);
assert!(matches!(
handle_key(
modified_key(KeyCode::Char('r'), KeyModifiers::ALT),
&mut state
),
InputAction::None
));
assert_eq!(state.selected, 0);
}
#[test]
fn left_and_right_collapse_and_expand_selected_activity() {
let mut state = state_with_parent_and_child();
assert_eq!(state.visible_nodes().len(), 2);
assert_eq!(state.selected, 0);
assert!(matches!(
handle_key(key(KeyCode::Left), &mut state),
InputAction::None
));
assert_eq!(state.visible_nodes().len(), 1);
assert_eq!(state.selected, 0);
assert_eq!(state.selected_activity_id().unwrap().as_str(), "parent");
assert!(matches!(
handle_key(key(KeyCode::Right), &mut state),
InputAction::None
));
assert_eq!(state.visible_nodes().len(), 2);
assert_eq!(state.selected, 0);
assert_eq!(state.selected_activity_id().unwrap().as_str(), "parent");
}
#[test]
fn left_right_on_leaf_are_no_ops() {
let mut state = state_with_parent_and_child();
state.selected = 1;
let child = state.selected_activity_id().unwrap();
let was_expanded = state.expanded.clone();
assert!(matches!(
handle_key(key(KeyCode::Left), &mut state),
InputAction::None
));
assert_eq!(state.selected, 1);
assert_eq!(state.selected_activity_id().unwrap(), child);
assert_eq!(state.expanded, was_expanded);
assert!(matches!(
handle_key(key(KeyCode::Right), &mut state),
InputAction::None
));
assert_eq!(state.selected, 1);
assert_eq!(state.selected_activity_id().unwrap(), child);
assert_eq!(state.expanded, was_expanded);
}
#[test]
fn changing_activity_selection_resets_detail() {
let mut state = state_with_activity();
for id in ["running", "failed"] {
state.apply_activity_event(ActivityEvent::Delta {
id: ActivityId::new(id),
preview: "detail row 1\ndetail row 2\ndetail row 3".to_string(),
});
}
state.focus_activity_tree();
state.scroll_detail_down();
assert_eq!(state.detail_offset(), 1);
assert!(matches!(
handle_key(key(KeyCode::Down), &mut state),
InputAction::None
));
assert_eq!(state.selected, 1);
assert_eq!(state.detail_offset(), 0);
state.scroll_detail_down();
assert!(matches!(
handle_key(
modified_key(KeyCode::Char('r'), KeyModifiers::ALT),
&mut state
),
InputAction::None
));
assert_eq!(state.selected, 0);
assert_eq!(state.detail_offset(), 0);
}
#[test]
fn collapse_all_clamps_child_selection_and_preserves_valid_detail() {
let mut state = MissionControlState {
focus_pane: crate::tui::state::TuiFocusPane::ActivityTree,
prompt_editor: crate::tui::state::PromptEditor::new("draft stays", "draft stays".len()),
transcript: vec!["you: existing".to_string()].into(),
..Default::default()
};
let parent = ActivityId::new("parent");
let child = ActivityId::new("child");
state.apply_activity_event(ActivityEvent::Started {
id: parent.clone(),
parent_id: None,
kind: ActivityKind::SubagentBatch,
status: ActivityStatus::Running,
metadata: ActivityMetadata::new("parent activity"),
});
state.apply_activity_event(ActivityEvent::Started {
id: child,
parent_id: Some(parent),
kind: ActivityKind::Tool,
status: ActivityStatus::Success,
metadata: ActivityMetadata::new("child activity"),
});
state.apply_activity_event(ActivityEvent::Delta {
id: ActivityId::new("child"),
preview: "detail row 1\ndetail row 2".to_string(),
});
assert_eq!(state.visible_nodes().len(), 2);
state.selected = 1;
state.scroll_detail_down();
assert!(matches!(
handle_key(
modified_key(KeyCode::Char('c'), KeyModifiers::ALT),
&mut state
),
InputAction::None
));
assert_eq!(state.visible_nodes().len(), 1);
assert_eq!(state.prompt_plain_text(), "draft stays");
assert_eq!(state.prompt_cursor(), "draft stays".len());
assert_eq!(state.transcript, vec!["you: existing".to_string()]);
assert_eq!(state.selected, 0);
assert_eq!(state.detail_offset(), 0);
let detail = state.selected_activity_text();
assert!(detail.contains("id: parent"));
assert!(detail.contains("label: parent activity"));
assert!(!detail.contains("No activity selected"));
}
#[test]
fn activity_arrows_still_control_activity_when_activity_focused() {
let mut state = state_with_activity();
state.focus_activity_tree();
assert!(matches!(
handle_key_with_viewport(key(KeyCode::Down), &mut state, None, &[]),
InputAction::None
));
assert_eq!(state.selected, 1);
assert_eq!(state.prompt_cursor(), 0);
}