use anstyle::Effects;
use insta::assert_snapshot;
use ratatui::{Terminal, backend::TestBackend};
use vtcode_core::ui::{
InlineHeaderContext, InlineMessageKind, InlineSegment, InlineTextStyle, InlineTheme,
};
use vtcode_core::ui::{SessionOptions, spawn_session_with_options};
#[test]
fn test_tui_with_conversation_history() {
let backend = TestBackend::new(80, 20);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
let area = f.area();
assert!(area.width > 0);
assert!(area.height > 0);
})
.unwrap();
assert_snapshot!(format!("{}", terminal.backend()));
}
#[tokio::test]
#[ignore] async fn test_real_ui_scenario_with_commands() {
let session = spawn_session_with_options(
InlineTheme::default(),
SessionOptions {
placeholder: Some("Type your message here...".to_string()),
inline_rows: 12,
..SessionOptions::default()
},
);
assert!(session.is_ok());
let session = session.unwrap();
session.handle.append_line(
InlineMessageKind::User,
vec![InlineSegment {
text: "Can you help me refactor this Rust code?".to_string(),
style: InlineTextStyle::default().into(),
}],
);
session.handle.append_line(
InlineMessageKind::Agent,
vec![InlineSegment {
text: "Sure! I can help you refactor your Rust code. Could you share the code you'd like to refactor?".to_string(),
style: InlineTextStyle::default().into(),
}],
);
session.handle.append_line(
InlineMessageKind::User,
vec![InlineSegment {
text: "Here's the code I want to refactor:\n```rust\nfn calculate_sum(numbers: Vec<i32>) -> i32 {\n let mut sum = 0;\n for i in 0..numbers.len() {\n sum += numbers[i];\n }\n sum\n}\n```".to_string(),
style: InlineTextStyle::default().into(),
}],
);
session.handle.append_line(
InlineMessageKind::Agent,
vec![InlineSegment {
text: "I can help refactor this code to be more idiomatic Rust. Here's an improved version:\n```rust\nfn calculate_sum(numbers: &[i32]) -> i32 {\n numbers.iter().sum()\n}\n```\nThis version: 1) Takes a slice instead of moving the Vec, 2) Uses iterator methods for better performance, 3) Is more idiomatic Rust.".to_string(),
style: InlineTextStyle::default().into(),
}],
);
assert!(!session.events.is_closed());
assert_snapshot!(
"real_ui_scenario_session",
format!("Session created with messages: 4")
);
}
#[test]
fn test_tui_with_different_header_contexts() {
let contexts = vec![
(
"basic_context",
InlineHeaderContext {
provider: "openai".to_string(),
model: "gpt-oss-20b".to_string(),
mode: "interactive".to_string(),
version: "test-version".to_string(),
..Default::default()
},
),
(
"advanced_context",
InlineHeaderContext {
provider: "anthropic".to_string(),
model: "claude-3".to_string(),
mode: "full-auto".to_string(),
reasoning: "analytical".to_string(),
version: "test-version".to_string(),
..Default::default()
},
),
(
"minimal_context",
InlineHeaderContext {
provider: "local".to_string(),
model: "llama3".to_string(),
mode: "inline".to_string(),
version: "test-version".to_string(),
..Default::default()
},
),
];
for (name, context) in contexts {
assert_snapshot!(format!("header_context_{}", name), format!("{:?}", context));
}
}
#[test]
fn test_ui_message_combinations() {
let test_cases = vec![
(
"user_agent_exchange",
vec![
(InlineMessageKind::User, "Hello!"),
(InlineMessageKind::Agent, "Hi there! How can I help you?"),
],
),
(
"error_scenario",
vec![
(InlineMessageKind::User, "Run this command"),
(
InlineMessageKind::Error,
"Command failed with error: Permission denied",
),
(
InlineMessageKind::Agent,
"I encountered an error. Would you like me to try again with sudo?",
),
],
),
(
"tool_usage",
vec![
(
InlineMessageKind::User,
"Show me files in current directory",
),
(InlineMessageKind::Tool, "run_pty_cmd([\"ls\", \"-la\"])"),
(InlineMessageKind::Pty, "file1.txt file2.rs src/"),
(
InlineMessageKind::Agent,
"I've listed the files in the current directory for you.",
),
],
),
];
for (name, messages) in test_cases {
let message_repr: Vec<String> = messages
.iter()
.map(|(kind, text)| format!("{:?}: {}", kind, text))
.collect();
assert_snapshot!(
format!("message_combo_{}", name),
format!("{:?}", message_repr)
);
}
}
#[test]
fn test_ui_styling_variations() {
let styled_segments = vec![
(
"plain_text",
InlineSegment {
text: "This is plain text".to_string(),
style: InlineTextStyle {
color: None,
bg_color: None,
effects: Effects::new(),
}
.into(),
},
),
(
"bold_text",
InlineSegment {
text: "This is bold text".to_string(),
style: InlineTextStyle {
color: None,
bg_color: None,
effects: Effects::BOLD,
}
.into(),
},
),
(
"italic_text",
InlineSegment {
text: "This is italic text".to_string(),
style: InlineTextStyle {
color: None,
bg_color: None,
effects: Effects::ITALIC,
}
.into(),
},
),
(
"bold_italic_text",
InlineSegment {
text: "This is bold and italic text".to_string(),
style: InlineTextStyle {
color: None,
bg_color: None,
effects: Effects::BOLD | Effects::ITALIC,
}
.into(),
},
),
];
for (name, segment) in styled_segments {
assert_snapshot!(format!("styled_segment_{}", name), format!("{:?}", segment));
}
}