use testty::assertion;
use testty::region::Region;
use testty::scenario::Scenario;
use crate::common;
use crate::common::{BuilderEnv, FeatureTest};
#[test]
fn session_list_empty_state() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
let scenario = Scenario::new("session_empty")
.compose(&common::wait_for_agentty_startup())
.viewing_pause_ms(1500)
.compose(&common::switch_to_tab("Sessions"))
.viewing_pause_ms(1500)
.capture_labeled("sessions_tab", "Sessions tab with no sessions");
let (frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(&frame, "No sessions", &full);
common::save_feature_gif(&scenario, &report, &env, "session_empty");
}
#[test]
fn session_creation_opens_prompt_mode() {
FeatureTest::new("session_creation")
.with_git()
.zola(
"Session creation",
"Start a new agent session with a single keypress.",
30,
)
.run(
|scenario| {
scenario
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.viewing_pause_ms(1500)
.press_key("a")
.wait_for_stable_frame(300, 5000)
.viewing_pause_ms(1500)
.capture_labeled("prompt_mode", "Prompt mode after pressing a")
},
|frame, _report| {
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(frame, "Enter: submit", &full);
assertion::assert_text_in_region(frame, "Esc: cancel", &full);
},
);
}
#[test]
fn session_prompt_cancel_returns_to_empty_list() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
env.init_git().expect("failed to init git");
let scenario = Scenario::new("prompt_cancel")
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.viewing_pause_ms(1500)
.press_key("a")
.wait_for_stable_frame(300, 5000)
.viewing_pause_ms(1500)
.press_key("Esc")
.wait_for_stable_frame(300, 5000)
.viewing_pause_ms(1500)
.capture_labeled("back_to_list", "Sessions list after cancel");
let (frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(&frame, "No sessions", &full);
common::save_feature_gif(&scenario, &report, &env, "prompt_cancel");
}
#[test]
fn session_open_and_return_to_list() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
env.init_git().expect("failed to init git");
let scenario = Scenario::new("open_and_return")
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.compose(&common::create_session_and_return_to_list())
.press_key("Enter")
.sleep(std::time::Duration::from_secs(2))
.capture_labeled("session_view", "Session view after Enter")
.press_key("q")
.sleep(std::time::Duration::from_secs(1))
.capture_labeled("back_to_list", "Sessions list after q");
let (frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let session_view_frame = common::frame_from_capture(&report.captures[0]);
let view_full = Region::full(session_view_frame.cols(), session_view_frame.rows());
assertion::assert_text_in_region(&session_view_frame, "q: back", &view_full);
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(&frame, "test", &full);
common::save_feature_gif(&scenario, &report, &env, "session_open");
}
#[test]
fn session_list_jk_navigation() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
env.init_git().expect("failed to init git");
let scenario = Scenario::new("jk_navigation")
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.compose(&common::create_session_with_prompt_and_return_to_list(
"alpha",
))
.compose(&common::create_session_with_prompt_and_return_to_list(
"beta",
))
.capture_labeled("two_sessions", "Two sessions in list")
.press_key("j")
.wait_for_stable_frame(300, 3000)
.press_key("Enter")
.sleep(std::time::Duration::from_secs(2))
.capture_labeled("opened_after_j", "Session opened after pressing j")
.press_key("q")
.sleep(std::time::Duration::from_secs(1))
.press_key("k")
.wait_for_stable_frame(300, 3000)
.press_key("Enter")
.sleep(std::time::Duration::from_secs(2))
.capture_labeled("opened_after_k", "Session opened after pressing k");
let (_frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let initial_frame = common::frame_from_capture(&report.captures[0]);
let opened_after_j_frame = common::frame_from_capture(&report.captures[1]);
let opened_after_k_frame = common::frame_from_capture(&report.captures[2]);
let initial_matches = initial_frame.find_text("alpha");
let initial_beta_matches = initial_frame.find_text("beta");
let opened_after_j_text = opened_after_j_frame.text_in_region(&Region::full(
opened_after_j_frame.cols(),
opened_after_j_frame.rows(),
));
let opened_after_k_text = opened_after_k_frame.text_in_region(&Region::full(
opened_after_k_frame.cols(),
opened_after_k_frame.rows(),
));
assert!(
!initial_matches.is_empty(),
"Expected at least 1 'alpha' match in initial frame, found {}",
initial_matches.len()
);
assert!(
!initial_beta_matches.is_empty(),
"Expected at least 1 'beta' match in initial frame, found {}",
initial_beta_matches.len()
);
assert!(
opened_after_j_text.contains("alpha") || opened_after_j_text.contains("beta"),
"Expected the session opened after j to contain either alpha or beta"
);
assert!(
opened_after_k_text.contains("alpha") || opened_after_k_text.contains("beta"),
"Expected the session opened after k to contain either alpha or beta"
);
assert_ne!(
opened_after_j_text.contains("alpha"),
opened_after_k_text.contains("alpha"),
"Expected j and k to open different sessions"
);
common::save_feature_gif(&scenario, &report, &env, "session_navigation");
}
#[test]
fn session_delete_with_confirmation() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
env.init_git().expect("failed to init git");
let scenario = Scenario::new("delete_confirmation")
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.compose(&common::create_session_and_return_to_list())
.viewing_pause_ms(1500)
.press_key("d")
.wait_for_stable_frame(300, 3000)
.viewing_pause_ms(1500)
.capture_labeled("confirm_dialog", "Delete confirmation dialog")
.press_key("y")
.wait_for_stable_frame(500, 10000)
.viewing_pause_ms(1500)
.capture_labeled("after_delete", "Sessions list after deletion");
let (frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let dialog_frame = common::frame_from_capture(&report.captures[0]);
let dialog_full = Region::full(dialog_frame.cols(), dialog_frame.rows());
assertion::assert_text_in_region(&dialog_frame, "Confirm Delete", &dialog_full);
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(&frame, "No sessions", &full);
common::save_feature_gif(&scenario, &report, &env, "session_delete");
}
#[test]
fn prompt_typing_shows_text() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
env.init_git().expect("failed to init git");
let scenario = Scenario::new("prompt_typing")
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.viewing_pause_ms(1500)
.press_key("a")
.wait_for_stable_frame(300, 5000)
.viewing_pause_ms(1000)
.write_text("hello world")
.wait_for_text("hello world", 3000)
.viewing_pause_ms(1500)
.capture_labeled("typed_text", "Prompt input with typed text");
let (frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(&frame, "hello world", &full);
common::save_feature_gif(&scenario, &report, &env, "prompt_typing");
}
#[test]
fn prompt_multiline_via_alt_enter() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let env = BuilderEnv::new(temp.path()).expect("failed to create builder env");
env.init_git().expect("failed to init git");
let scenario = Scenario::new("prompt_multiline")
.compose(&common::wait_for_agentty_startup())
.compose(&common::switch_to_tab("Sessions"))
.viewing_pause_ms(1500)
.press_key("a")
.wait_for_stable_frame(300, 5000)
.viewing_pause_ms(1000)
.write_text("first line")
.wait_for_text("first line", 3000)
.viewing_pause_ms(1000)
.write_text("\x1b\r")
.wait_for_stable_frame(300, 3000)
.write_text("second line")
.wait_for_text("second line", 3000)
.viewing_pause_ms(1500)
.capture_labeled("multiline", "Prompt input with multiline text");
let (frame, report) = scenario
.run_with_proof(env.builder())
.expect("scenario execution failed");
let full = Region::full(frame.cols(), frame.rows());
assertion::assert_text_in_region(&frame, "first line", &full);
assertion::assert_text_in_region(&frame, "second line", &full);
common::save_feature_gif(&scenario, &report, &env, "prompt_multiline");
}