#[cfg(test)]
#[path = "ui_snapshot_claims.rs"]
mod claims;
#[cfg(test)]
#[path = "ui_snapshot_cursor_labels.rs"]
mod cursor_labels;
#[cfg(test)]
#[path = "ui_snapshot_drafts.rs"]
mod drafts;
#[cfg(test)]
#[path = "ui_snapshot_fold_composer.rs"]
mod fold_composer;
#[cfg(test)]
#[path = "ui_snapshot_gate_action.rs"]
mod gate_action;
#[cfg(test)]
#[path = "ui_snapshot_splash_wide.rs"]
mod splash_wide;
#[cfg(test)]
#[path = "ui_snapshot_support.rs"]
mod support;
#[cfg(test)]
#[path = "ui_snapshot_tables.rs"]
mod tables;
pub(crate) use claims::{proposed_claim, supplied_claim, supplied_contract};
pub(crate) use support::{empty_app, fixed_status, render_buffer, unused_runtime, unused_store};
use super::stream_events::apply_event;
use saya_agent::{AgentEvent, KnowledgeOutcome};
use saya_types::ClaimStatus;
#[test]
fn memory_receipt_above_answer() {
let mut app = empty_app();
apply_event(
&mut app.transcript,
AgentEvent::knowledge_supplied(
KnowledgeOutcome::Ran {
store_unavailable: false,
},
vec![supplied_contract(
"analytics",
"catalog.public.orders",
"current",
vec![
supplied_claim(
"ki-abcdef1234",
"table_alias",
"orders",
None,
ClaimStatus::Confirmed,
),
supplied_claim(
"ki-bbbedcafe",
"default_time_column",
"created_at",
Some("created_at"),
ClaimStatus::Candidate,
),
],
)],
0,
),
false,
);
apply_event(
&mut app.transcript,
AgentEvent::assistant_text("The orders table uses created_at as its time column."),
false,
);
let buffer = render_buffer(&app, &fixed_status(), 80, 24);
insta::assert_snapshot!(buffer);
}
#[test]
fn learned_and_noted_trailing_answer() {
let mut app = empty_app();
apply_event(
&mut app.transcript,
AgentEvent::assistant_text("Done — I've recorded what you told me and flagged the guess."),
false,
);
apply_event(
&mut app.transcript,
AgentEvent::knowledge_proposed(proposed_claim(
"ki-learned1",
"analytics",
"catalog.public.orders",
"table_alias",
"orders",
None,
ClaimStatus::Confirmed,
)),
false,
);
apply_event(
&mut app.transcript,
AgentEvent::knowledge_proposed(proposed_claim(
"ki-noted1",
"analytics",
"catalog.public.orders",
"default_time_column",
"created_at",
Some("created_at"),
ClaimStatus::Candidate,
)),
false,
);
let buffer = render_buffer(&app, &fixed_status(), 80, 24);
insta::assert_snapshot!(buffer);
}
#[test]
fn a_folded_chapter_paints_its_request_as_one_row() {
use super::transcript::BlockKind;
let mut app = empty_app();
app.transcript.push(BlockKind::User, "count the red orders");
app.transcript
.push(BlockKind::Assistant, "the red orders total 42");
app.transcript.push(BlockKind::User, "and the blue ones");
let unfolded_rows = app.transcript.total_lines(78);
assert!(app.transcript.toggle_chapter(1));
let folded_rows = app.transcript.total_lines(78);
assert!(
folded_rows < unfolded_rows,
"folding removes painted rows ({unfolded_rows} -> {folded_rows})"
);
let folded = render_buffer(&app, &fixed_status(), 80, 24);
assert!(
folded.contains("count the red orders"),
"the folded screen keeps the verbatim request:\n{folded}"
);
assert!(
!folded.contains("the red orders total 42"),
"the hidden answer leaves the screen:\n{folded}"
);
insta::assert_snapshot!(folded);
}
#[test]
fn approval_modal_renders_the_shared_fact_body() {
let mut app = empty_app();
let tool = crate::interactive::session_definitions::http_fetch();
let arguments = serde_json::json!({"url": "https://api.github.com/repos/x/y"});
let facts = crate::approval_facts::ApprovalFacts {
fetch: Some(crate::approval_facts::FetchFacts {
fetch_body_bytes: 61_440,
fetch_seconds: 30,
fetch_redirects: 5,
download: None,
}),
..crate::approval_facts::ApprovalFacts::default()
};
let grant = crate::grant_token::grant_token(&tool.name, &arguments, None, &facts);
let detail = crate::approval_facts::call_facts(
&tool.name,
&arguments,
grant.as_deref(),
&facts,
None,
None,
);
let (respond, _answer) = tokio::sync::oneshot::channel();
app.request.pending_approval = Some(super::types::PendingApproval {
tool: tool.name.clone(),
detail,
grant,
scroll: 0,
respond,
});
let buffer = render_buffer(&app, &fixed_status(), 80, 24);
insta::assert_snapshot!(buffer);
}
#[test]
fn new_activity_below_the_fold_shows_the_count_and_the_key_back() {
use super::transcript::BlockKind;
let mut app = empty_app();
for i in 0..12 {
app.transcript
.push(BlockKind::Assistant, format!("line {i}"));
}
app.transcript.scroll_up(3, 78, 8);
let _ = app.transcript.view(78, 8);
app.transcript
.push(BlockKind::Assistant, "a late answer lands");
assert!(
app.unseen_new_rows() > 0,
"precondition: the row landed below the fold"
);
let buffer = render_buffer(&app, &fixed_status(), 80, 24);
assert!(
buffer.contains("new line"),
"the bar names the arrival:\n{buffer}"
);
assert!(
buffer.contains("Shift+End"),
"the bar names the key back:\n{buffer}"
);
insta::assert_snapshot!(buffer);
}
#[cfg(test)]
#[path = "ui_snapshot_output_scope.rs"]
mod output_scope;