#[cfg(test)]
mod user_behavioral_component_tests {
use crate::model::choice::Choice;
use crate::model::common::{Stream, StreamType};
use std::time::SystemTime;
#[test]
fn user_expects_active_tab_appears_selected() {
let mut streams = Vec::new();
streams.push(Stream {
id: "tab1".to_string(),
stream_type: StreamType::Content,
content: vec!["Tab 1 content".to_string()],
label: "Tab 1".to_string(),
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
});
streams.push(Stream {
id: "tab2".to_string(),
stream_type: StreamType::RedirectedOutput("tab2_redirect".to_string()),
content: vec!["Tab 2 content".to_string()],
label: "Tab 2".to_string(),
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
});
let active_tab = streams.iter().find(|s| s.id == "tab1").unwrap(); let inactive_tab = streams.iter().find(|s| s.id == "tab2").unwrap();
assert_eq!(active_tab.label, "Tab 1");
assert_eq!(inactive_tab.label, "Tab 2");
assert_eq!(active_tab.id, "tab1");
assert_eq!(inactive_tab.id, "tab2");
let active_count = 1; assert_eq!(active_count, 1, "User expects exactly one active tab");
println!("✓ User behavioral test: Active tab appears selected");
}
#[test]
fn user_expects_tab_switching_changes_active_tab() {
let mut streams = Vec::new();
streams.push(Stream {
id: "tab1".to_string(),
stream_type: StreamType::Content,
label: "Tab 1".to_string(),
content: vec!["Tab 1 content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
});
streams.push(Stream {
id: "tab2".to_string(),
stream_type: StreamType::RedirectedOutput("tab2_redirect".to_string()),
label: "Tab 2".to_string(),
content: vec!["Tab 2 content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
});
let selected_stream_id = "tab2".to_string();
let active_tab = streams.iter().find(|s| s.id == selected_stream_id).unwrap();
assert_eq!(active_tab.id, "tab2");
assert_eq!(active_tab.label, "Tab 2");
let tab1 = streams.iter().find(|s| s.id == "tab1").unwrap();
assert_ne!(tab1.id, selected_stream_id);
println!("✓ User behavioral test: Tab switching changes active tab");
}
#[test]
fn user_expects_closeable_streams_have_close_button() {
let closeable_stream = Stream {
id: "closeable".to_string(),
stream_type: StreamType::RedirectedOutput("closeable_redirect".to_string()),
label: "Closeable Tab".to_string(),
content: vec!["Closeable content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
};
let non_closeable_stream = Stream {
id: "default".to_string(),
stream_type: StreamType::Content,
label: "Default Tab".to_string(),
content: vec!["Default content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
};
assert!(
closeable_stream.stream_type != StreamType::Content,
"User expects redirected streams to be closeable"
);
assert_eq!(
non_closeable_stream.stream_type,
StreamType::Content,
"User expects default content stream to always be present"
);
println!("✓ User behavioral test: Closeable streams have close capability");
}
#[test]
fn user_expects_closing_stream_removes_it() {
let mut streams = vec![
Stream {
id: "default".to_string(),
stream_type: StreamType::Content,
label: "Default".to_string(),
content: vec!["Default content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
Stream {
id: "closeable".to_string(),
stream_type: StreamType::RedirectedOutput("closeable_redirect".to_string()),
label: "Closeable".to_string(),
content: vec!["Closeable content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
];
assert_eq!(streams.len(), 2, "Should start with 2 streams");
streams.retain(|stream| stream.stream_type == StreamType::Content);
assert_eq!(
streams.len(),
1,
"User expects closeable stream to be removed"
);
assert_eq!(streams[0].stream_type, StreamType::Content);
println!("✓ User behavioral test: Closing stream removes it");
}
#[test]
fn user_expects_choice_click_executes_script() {
let choice = Choice {
id: "test_choice".to_string(),
content: Some("Execute Me".to_string()),
script: Some(vec!["echo 'Choice executed'".to_string()]),
waiting: false,
..Default::default()
};
assert!(
choice.script.is_some(),
"User expects choice to have executable action"
);
assert_eq!(choice.script.unwrap(), vec!["echo 'Choice executed'"]);
assert!(
!choice.waiting,
"User expects choice to be ready for execution"
);
println!("✓ User behavioral test: Choice click executes script");
}
#[test]
fn user_expects_waiting_choice_shows_indicator() {
let mut choice = Choice {
id: "waiting_choice".to_string(),
content: Some("Long Running Task".to_string()),
script: Some(vec!["sleep 5".to_string()]),
waiting: false,
..Default::default()
};
choice.waiting = true;
assert!(
choice.waiting,
"User expects waiting choice to be marked as waiting"
);
assert_eq!(
choice.content,
Some("Long Running Task".to_string()),
"User expects choice content to describe its purpose"
);
println!("✓ User behavioral test: Waiting choice shows indicator");
}
#[test]
fn user_expects_scrollbar_appears_for_long_content() {
let container_height = 5;
let short_content = vec!["Line 1".to_string(), "Line 2".to_string()];
let short_needs_scrollbar = short_content.len() > (container_height - 2);
let long_content = vec![
"Line 1".to_string(),
"Line 2".to_string(),
"Line 3".to_string(),
"Line 4".to_string(),
"Line 5".to_string(),
"Line 6".to_string(),
"Line 7".to_string(),
"Line 8".to_string(),
];
let long_needs_scrollbar = long_content.len() > (container_height - 2);
assert!(
!short_needs_scrollbar,
"User expects no scrollbar for content that fits"
);
assert!(
long_needs_scrollbar,
"User expects scrollbar when content exceeds container"
);
println!("✓ User behavioral test: Scrollbar appears for long content");
}
#[test]
fn user_expects_stream_content_updates() {
let mut stream = Stream {
id: "updatable_stream".to_string(),
stream_type: StreamType::Content,
content: vec!["Initial content".to_string()],
label: "Updatable Stream".to_string(),
source: None,
choices: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
};
assert_eq!(stream.content, vec!["Initial content"]);
stream.content = vec!["Updated content".to_string()];
assert_eq!(stream.content, vec!["Updated content"]);
assert_eq!(stream.id, "updatable_stream");
assert_eq!(stream.label, "Updatable Stream");
println!("✓ User behavioral test: Stream content updates correctly");
}
}