test(pty): assert the save-as receipt across wrapped transcript rows

release_fleet_route_save_journey asserted the "user-global default"
fragment on a single screen row, but the receipt wraps after the written
Fleet path and the wrap point moves with the temp-dir path length. Under
the release-gate TMPDIR the break landed between "user-global" and
"default", so the assertion timed out although the save-as had happened
exactly as claimed. Rejoin transcript continuation rows before asserting so
the check is about the receipt, not the terminal width or temp path.
This commit is contained in:
CodeWhale Bot
2026-08-15 18:08:35 -07:00
parent a9dc9f6783
commit 533c530be4

View File

@@ -11,6 +11,7 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{Duration, Instant};
use crate::qa_harness::frame::Frame;
use crate::qa_harness::harness::{Harness, SealedWorkspace, make_sealed_workspace};
use crate::qa_harness::keys;
use anyhow::{Result, anyhow};
@@ -279,6 +280,26 @@ fn wait_for_counter(
}
}
/// Screen text with transcript continuation rows (`▏` gutter) rejoined to
/// the row they wrap from, so a receipt can be asserted regardless of where
/// the terminal width breaks it.
fn unwrapped_transcript(frame: &Frame) -> String {
let mut out = String::new();
for row in 0..frame.rows() {
let text = frame.row(row);
if let Some(rest) = text.strip_prefix('▏') {
out.push(' ');
out.push_str(rest.trim_start());
} else {
if !out.is_empty() {
out.push('\n');
}
out.push_str(&text);
}
}
out
}
fn type_and_submit(harness: &mut Harness, text: &str) -> Result<()> {
harness.send(keys::key::text(text))?;
// Rapid PTY writes intentionally exercise paste-burst detection. Wait
@@ -2071,10 +2092,14 @@ base_url = "{base_url}"
type_and_submit(&mut tui, "/model deepseek-v4-flash")?;
tui.wait_for_text("session only", INTERACTION_TIMEOUT)?;
type_and_submit(&mut tui, "/fleet save-as")?;
// The receipt wraps across lines at this width; assert on fragments that
// land on a single row.
// The receipt wraps across rows at this width and the wrap point moves
// with the temp-dir path length, so assert on the receipt with its
// transcript continuation rows rejoined rather than on any one row.
tui.wait_for_text("as new Fleet", INTERACTION_TIMEOUT)?;
tui.wait_for_text("user-global default", INTERACTION_TIMEOUT)?;
tui.wait_for(
|frame| unwrapped_transcript(frame).contains("user-global default"),
INTERACTION_TIMEOUT,
)?;
// The new Fleet is named after the route: `DeepSeek deepseek-v4-flash`.
let second_file = ws
.home()