use super::*;
#[test]
fn render_skill_autocomplete_popup_title_and_rows() {
let mut state = MissionControlState {
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
input: "$ru".to_string(),
prompt_cursor: 3,
..Default::default()
};
state.autocomplete = Some(crate::tui::state::AutocompleteState {
candidates: vec![crate::tui::state::AutocompleteCandidate::skill_tag(
"rust-dev",
)],
selected: 0,
token_start: 0,
token_end: 3,
token: "$ru".to_string(),
});
let backend = TestBackend::new(80, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let rendered = terminal
.backend()
.buffer()
.content()
.iter()
.map(|cell| cell.symbol())
.collect::<String>();
assert!(rendered.contains("Skill tags"), "{rendered}");
assert!(rendered.contains("$rust-dev"), "{rendered}");
assert!(rendered.contains("skill"), "{rendered}");
}
#[test]
fn render_prompt_shows_provider_model_and_thinking_on_bottom_right_border() {
let mut state = MissionControlState {
provider: "openai-codex".to_string(),
model: "gpt-5.5".to_string(),
provider_ready: true,
thinking_levels: crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
..Default::default()
};
state.refresh_thinking_levels(
crate::thinking::ThinkingLevel::High,
state.thinking_levels.clone(),
);
let backend = TestBackend::new(100, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
let metadata = find_text(buffer, " • openai-codex • gpt-5.5 • Thinking: High [Alt-T]").unwrap();
let alt_t = find_text(buffer, "[Alt-T]").unwrap();
let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
assert_eq!(metadata.1, layout.prompt.y + layout.prompt.height - 1);
assert!(alt_t.0 > layout.prompt.x + layout.prompt.width / 2);
}
#[test]
fn render_prompt_shows_alt_m_hint_when_idle() {
let mut state = MissionControlState {
provider: "zai".to_string(),
model: "glm-5.2".to_string(),
provider_ready: true,
thinking_levels: crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
..Default::default()
};
state.refresh_thinking_levels(
crate::thinking::ThinkingLevel::High,
state.thinking_levels.clone(),
);
let backend = TestBackend::new(100, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
assert!(
find_text(buffer, "[Alt-M]").is_some(),
"Alt-M hint should show when idle"
);
let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
let hint = find_text(buffer, "[Alt-M]").unwrap();
assert_eq!(hint.1, layout.prompt.y + layout.prompt.height - 1);
}
#[test]
fn render_prompt_hides_alt_m_hint_while_running() {
let mut state = MissionControlState {
provider: "zai".to_string(),
model: "glm-5.2".to_string(),
provider_ready: true,
thinking_levels: crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
..Default::default()
};
state.refresh_thinking_levels(
crate::thinking::ThinkingLevel::High,
state.thinking_levels.clone(),
);
state.start_running_prompt("inspect".to_string());
let backend = TestBackend::new(100, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
assert!(
find_text(buffer, "[Alt-M]").is_none(),
"Alt-M hint should hide while running"
);
}
#[test]
fn render_running_status_and_cancel_hint_on_prompt_top_left_only() {
let mut state = MissionControlState {
status: "running prompt…".to_string(),
provider_ready: true,
..Default::default()
};
state.start_running_prompt("inspect".to_string());
let backend = TestBackend::new(100, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
let status = find_text_in_area(buffer, layout.prompt, "running prompt…").expect("status");
let cancel = find_text_in_area(buffer, layout.prompt, "[Alt-C]").expect("cancel hint");
assert_eq!(status.1, layout.prompt.y);
assert_eq!(cancel.1, layout.prompt.y);
assert!(status.0 < layout.prompt.x + layout.prompt.width / 2);
let transcript = rendered_text_in_area(buffer, layout.transcript);
assert!(!transcript.contains("run ◐"), "{transcript}");
assert!(!transcript.contains("running prompt…"), "{transcript}");
assert!(!transcript.contains("[Alt-C]"), "{transcript}");
}
#[test]
fn render_prompt_shows_pending_steering_count_on_top_left_border() {
let state = MissionControlState {
pending_steering_count: 3,
provider_ready: true,
..Default::default()
};
let backend = TestBackend::new(100, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
let queued = find_text_in_area(buffer, layout.prompt, "3 steering queued").expect("queued");
assert_eq!(queued.1, layout.prompt.y);
let transcript = rendered_text_in_area(buffer, layout.transcript);
assert!(!transcript.contains("3 steering queued"), "{transcript}");
}
#[test]
fn render_prompt_hides_pending_steering_count_when_clear() {
let state = MissionControlState {
pending_steering_count: 0,
provider_ready: true,
..Default::default()
};
let backend = TestBackend::new(100, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let rendered = terminal
.backend()
.buffer()
.content()
.iter()
.map(|cell| cell.symbol())
.collect::<String>();
assert!(!rendered.contains("steering queued"));
}
#[test]
fn render_shows_block_prompt_cursor_when_prompt_focused() {
let mut state = MissionControlState {
input: "hello".to_string(),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
prompt_cursor_visible: true,
..Default::default()
};
let backend = TestBackend::new(80, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
assert!(find_text(buffer, "hello").is_some());
assert!(find_text(buffer, "█").is_some());
assert!(find_text(buffer, "▏").is_none());
state.prompt_cursor_visible = false;
terminal.draw(|frame| draw(frame, &state)).unwrap();
let blink_off_buffer = terminal.backend().buffer();
assert!(find_text(blink_off_buffer, "hello").is_some());
assert!(find_text(blink_off_buffer, "█").is_none());
state.focus_activity_tree();
state.prompt_cursor_visible = true;
terminal.draw(|frame| draw(frame, &state)).unwrap();
let activity_focus_buffer = terminal.backend().buffer();
assert!(find_text(activity_focus_buffer, "hello").is_some());
assert!(find_text(activity_focus_buffer, "█").is_none());
}
#[test]
fn render_places_prompt_cursor_at_logical_position() {
let state = MissionControlState {
input: "abcd".to_string(),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
prompt_cursor_visible: true,
prompt_cursor: 2,
..Default::default()
};
let backend = TestBackend::new(40, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
let prompt_area = layout_for(Rect::new(0, 0, 40, 20), &state).prompt;
let text_area = content_text_area_for_pane(TuiPane::Prompt, prompt_area);
let ab = find_text_in_area(buffer, text_area, "ab").unwrap();
let cursor = find_text_in_area(buffer, text_area, "█").unwrap();
let cd = find_text_in_area(buffer, text_area, "cd").unwrap();
assert_eq!(ab.1, cursor.1);
assert_eq!(cursor.1, cd.1);
assert!(ab.0 < cursor.0 && cursor.0 < cd.0);
}
#[test]
fn render_prompt_preserves_explicit_newlines_with_cursor_styling() {
let state = MissionControlState {
input: "ALPHA\nBETA".to_string(),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
prompt_cursor_visible: true,
prompt_cursor: "ALPHA\nBE".len(),
..Default::default()
};
let backend = TestBackend::new(80, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
let prompt_area = layout_for(Rect::new(0, 0, 80, 20), &state).prompt;
let alpha = find_text_in_area(buffer, prompt_area, "ALPHA").unwrap();
let be = find_text_in_area(buffer, prompt_area, "BE").unwrap();
let cursor = find_text_in_area(buffer, prompt_area, "█").unwrap();
let ta = find_text_in_area(buffer, prompt_area, "TA").unwrap();
assert_eq!(be.1, alpha.1 + 1);
assert_eq!(cursor.1, be.1);
assert_eq!(ta.1, be.1);
assert!(be.0 < cursor.0 && cursor.0 < ta.0);
assert_eq!(buffer[cursor].fg, MATRIX_GREEN.green_neon);
assert_eq!(buffer[cursor].bg, MATRIX_GREEN.background);
assert_eq!(buffer[alpha].fg, MATRIX_GREEN.text);
assert_eq!(buffer[be].fg, MATRIX_GREEN.text);
assert_eq!(buffer[ta].fg, MATRIX_GREEN.text);
}
#[test]
fn render_prompt_can_show_start_after_cursor_auto_reveal() {
let mut state = MissionControlState {
input: format!("HEAD{}TAIL", "x".repeat(130)),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
prompt_cursor_visible: true,
prompt_cursor: 0,
..Default::default()
};
state.ensure_prompt_cursor_visible(5, 16);
let backend = TestBackend::new(20, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let rendered = terminal
.backend()
.buffer()
.content()
.iter()
.map(|cell| cell.symbol())
.collect::<String>();
assert!(rendered.contains("HEAD"));
assert!(!rendered.contains("TAIL"));
}
#[test]
fn render_prompt_tails_overflow_after_five_wrapped_rows() {
let mut state = MissionControlState {
input: format!("HEAD{}TAIL", "x".repeat(75)),
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
prompt_cursor_visible: true,
..Default::default()
};
state.prompt_cursor = state.input.len();
state.ensure_prompt_cursor_visible(5, 14);
let backend = TestBackend::new(20, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let rendered = terminal
.backend()
.buffer()
.content()
.iter()
.map(|cell| cell.symbol())
.collect::<String>();
assert!(rendered.contains("TAIL"));
assert!(!rendered.contains("HEAD"));
}
#[test]
fn render_autocomplete_popup_when_visible() {
let state = state_with_autocomplete();
let backend = TestBackend::new(80, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let rendered = terminal
.backend()
.buffer()
.content()
.iter()
.map(|cell| cell.symbol())
.collect::<String>();
assert!(rendered.contains("Slash commands"));
assert!(rendered.contains("/new"));
assert!(rendered.contains("start a new session"));
}
#[test]
fn render_autocomplete_popup_uses_themed_background_and_selection() {
let mut state = MissionControlState {
input: "/".to_string(),
prompt_cursor: 1,
focus_pane: crate::tui::state::TuiFocusPane::Prompt,
..Default::default()
};
state.recompute_autocomplete(&[
crate::tui::state::AutocompleteCandidate::slash_command("new", "start a new session"),
crate::tui::state::AutocompleteCandidate::slash_command("quit", "exit magi-code"),
]);
let backend = TestBackend::new(80, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let buffer = terminal.backend().buffer();
let title = find_text(buffer, "Slash commands").unwrap();
assert_eq!(buffer[title].fg, MATRIX_GREEN.green_neon);
assert_eq!(buffer[title].bg, MATRIX_GREEN.panel_alt);
let selected = find_text(buffer, "/new").unwrap();
assert_eq!(buffer[selected].fg, MATRIX_GREEN.text);
assert_eq!(buffer[selected].bg, MATRIX_GREEN.selection);
let description = find_text(buffer, "start a new session").unwrap();
assert_eq!(buffer[description].fg, MATRIX_GREEN.text);
assert_eq!(buffer[description].bg, MATRIX_GREEN.selection);
let unselected = find_text(buffer, "/quit").unwrap();
assert_eq!(buffer[unselected].fg, MATRIX_GREEN.green_bright);
assert_eq!(buffer[unselected].bg, MATRIX_GREEN.panel_alt);
}
#[test]
fn render_autocomplete_popup_absent_when_hidden() {
let state = MissionControlState::default();
let backend = TestBackend::new(80, 20);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
let rendered = terminal
.backend()
.buffer()
.content()
.iter()
.map(|cell| cell.symbol())
.collect::<String>();
assert!(!rendered.contains("Slash commands"));
}
#[test]
fn render_autocomplete_small_terminal_does_not_panic() {
let state = state_with_autocomplete();
let backend = TestBackend::new(12, 5);
let mut terminal = ratatui::Terminal::new(backend).unwrap();
terminal.draw(|frame| draw(frame, &state)).unwrap();
}