test: record panel tui e2e evidence
This commit is contained in:
@@ -638,6 +638,43 @@ impl PanelHarness {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_len(&self) -> usize {
|
||||
self.output.lock().map(|output| output.len()).unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn wait_for_output_contains_from(
|
||||
&mut self,
|
||||
start_offset: usize,
|
||||
needle: &str,
|
||||
timeout: Duration,
|
||||
) -> Result<()> {
|
||||
let start = Instant::now();
|
||||
let needle = needle.as_bytes();
|
||||
loop {
|
||||
if self.output_after(start_offset, needle) {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(status) = self.child.try_wait()? {
|
||||
self.flush_output_artifact()?;
|
||||
return Err(HarnessError::Protocol(format!(
|
||||
"process exited with {status} before PTY output contained {:?}",
|
||||
String::from_utf8_lossy(needle)
|
||||
)));
|
||||
}
|
||||
if start.elapsed() >= timeout {
|
||||
self.flush_output_artifact()?;
|
||||
return Err(HarnessError::Timeout {
|
||||
what: format!(
|
||||
"PTY output containing {:?} after offset {start_offset}",
|
||||
String::from_utf8_lossy(needle)
|
||||
),
|
||||
artifacts: self.artifacts.clone(),
|
||||
});
|
||||
}
|
||||
thread::sleep(Duration::from_millis(20));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn events(&mut self) -> Result<Vec<HarnessEvent>> {
|
||||
let text = fs::read_to_string(&self.artifacts.events_jsonl)?;
|
||||
text.lines()
|
||||
@@ -684,6 +721,21 @@ impl PanelHarness {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn output_after(&self, start_offset: usize, needle: &[u8]) -> bool {
|
||||
if needle.is_empty() {
|
||||
return true;
|
||||
}
|
||||
self.output
|
||||
.lock()
|
||||
.map(|output| {
|
||||
let start = start_offset.min(output.len());
|
||||
output[start..]
|
||||
.windows(needle.len())
|
||||
.any(|window| window == needle)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn mouse_capture_enabled(&self) -> bool {
|
||||
self.output
|
||||
.lock()
|
||||
|
||||
@@ -135,14 +135,20 @@ fn panel_ctrl_c_exits_promptly_after_background_barrier() -> yoi_e2e::Result<()>
|
||||
"quit latency {elapsed:?} exceeded threshold; artifacts at {}",
|
||||
panel.artifacts().dir.display()
|
||||
);
|
||||
let events = panel.events()?;
|
||||
assert!(
|
||||
panel
|
||||
.events()?
|
||||
.iter()
|
||||
.any(|event| event.event == "quit_requested"),
|
||||
events.iter().any(|event| event.event == "quit_requested"),
|
||||
"quit_requested observability event missing; artifacts at {}",
|
||||
panel.artifacts().dir.display()
|
||||
);
|
||||
assert!(
|
||||
events.iter().any(|event| {
|
||||
event.event == "background_task_aborted"
|
||||
&& event.data.get("task").and_then(serde_json::Value::as_str) == Some("reload")
|
||||
}),
|
||||
"pending reload task should be aborted before quit completes; artifacts at {}",
|
||||
panel.artifacts().dir.display()
|
||||
);
|
||||
drop(panel);
|
||||
assert_fixture_cleanup(fixture.cleanup()?);
|
||||
Ok(())
|
||||
|
||||
@@ -13,6 +13,7 @@ fn single_pod_rewind_picker_applies_without_escape_and_suppresses_duplicate_ente
|
||||
tui.assert_no_full_drag_mouse_capture()?;
|
||||
tui.expect_event("rewind_fixture_ready", Duration::from_secs(5))?;
|
||||
|
||||
let before_rewind_output = tui.output_len();
|
||||
tui.press(KeyPress::CtrlR)?;
|
||||
tui.expect_event("rewind_picker_opened", Duration::from_secs(5))?;
|
||||
|
||||
@@ -34,10 +35,15 @@ fn single_pod_rewind_picker_applies_without_escape_and_suppresses_duplicate_ente
|
||||
.data
|
||||
.get("composer_text")
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("revise the plan"),
|
||||
Some("rewind-live-refresh"),
|
||||
"rewind should update the visible composer state without Esc/restart; artifacts at {}",
|
||||
tui.artifacts().dir.display()
|
||||
);
|
||||
tui.wait_for_output_contains_from(
|
||||
before_rewind_output,
|
||||
"rewind-live-refresh",
|
||||
Duration::from_secs(5),
|
||||
)?;
|
||||
assert_eq!(
|
||||
tui.count_events("rewind_submit_sent")?,
|
||||
submit_count,
|
||||
|
||||
Reference in New Issue
Block a user