test(tui): cover Markdown drag-copy with regression tests (#6156)

Three focused tests in mouse_ui/primary_tests.rs: default-on Markdown
payload preserving fences with a cell-count toast, rendered-text
fallback when selection_copy_markdown=false, and multi-cell blank-line
join with count. Update
mouse_selection_autocopies_on_release_without_ctrl_c for the toast
receipt (clipboard assertion unchanged).

Validation: tui::mouse_ui::primary_tests 8 passed, 0 failed;
updated ui test 1 passed; updated ui test FAILS without the fix
(status-sink assertion), proving it pins the new behavior.
This commit is contained in:
Hunter B committed 2026-09-13 22:18:57 -07:00
1 parent 3b29358469
commit 0dc66e6166
2 files changed
+125 -1

No files matched your search

@@ -209,3 +209,115 @@ fn transcript_drag_released_over_composer_keeps_caret_and_clears_drag() {
assert_eq!(app.clipboard.read_primary_text(), Some(expected));
assert_eq!(app.clipboard.last_written_text(), Some("REGULAR_CLIPBOARD"));
}
fn select_all_transcript_lines(app: &mut App) {
let last = app
.viewport
.transcript_cache
.lines()
.len()
.saturating_sub(1);
app.viewport.transcript_selection.anchor = Some(TranscriptSelectionPoint {
line_index: 0,
column: 0,
});
app.viewport.transcript_selection.head = Some(TranscriptSelectionPoint {
line_index: last,
column: 80,
});
}
fn ensure_transcript(app: &mut App) {
app.resync_history_revisions();
app.viewport.transcript_cache.ensure(
&app.history,
&app.history_revisions,
80,
app.transcript_render_options(),
);
}
#[test]
fn transcript_copy_defaults_to_markdown_source_and_names_cell_count() {
let (mut app, _) = composer();
assert!(
app.viewport.selection_copy_markdown,
"markdown copy defaults on"
);
let content = "# Title\n\n```rust\nlet x = 1;\n```".to_string();
app.history = vec![HistoryCell::Assistant {
content: content.clone(),
streaming: false,
}];
ensure_transcript(&mut app);
select_all_transcript_lines(&mut app);
let toasts_before = app.status_toasts.len();
copy_active_selection(&mut app);
assert_eq!(app.clipboard.last_written_text(), Some(content.as_str()));
assert_eq!(app.status_toasts.len(), toasts_before + 1);
let toast = app.status_toasts.back().expect("markdown copy toast");
assert!(
toast.text.contains("(1)"),
"toast names the projected cell count, got {:?}",
toast.text
);
assert!(
app.status_message.is_none(),
"toast path must not touch the legacy status sink"
);
}
#[test]
fn transcript_copy_falls_back_to_rendered_text_when_markdown_is_off() {
let (mut app, _) = composer();
app.viewport.selection_copy_markdown = false;
app.history = vec![HistoryCell::Assistant {
content: "# Title\n\n```rust\nlet x = 1;\n```".to_string(),
streaming: false,
}];
ensure_transcript(&mut app);
select_all_transcript_lines(&mut app);
let expected = selection_to_text(&app).expect("rendered fallback text");
let toasts_before = app.status_toasts.len();
copy_active_selection(&mut app);
assert_eq!(
app.clipboard.last_written_text(),
Some(expected.as_str())
);
assert_eq!(app.status_message.as_deref(), Some("Selection copied"));
assert_eq!(app.status_toasts.len(), toasts_before);
}
#[test]
fn transcript_copy_joins_cells_with_blank_lines_and_counts_them() {
let (mut app, _) = composer();
app.history = vec![
HistoryCell::User {
content: "first question".into(),
},
HistoryCell::Assistant {
content: "second answer".into(),
streaming: false,
},
];
ensure_transcript(&mut app);
select_all_transcript_lines(&mut app);
// A partial drag still rounds out to whole cells.
app.viewport.transcript_selection.anchor = Some(TranscriptSelectionPoint {
line_index: 0,
column: 2,
});
let toasts_before = app.status_toasts.len();
copy_active_selection(&mut app);
assert_eq!(
app.clipboard.last_written_text(),
Some("first question\n\nsecond answer")
);
assert_eq!(app.status_toasts.len(), toasts_before + 1);
let toast = app.status_toasts.back().expect("multi-cell copy toast");
assert!(
toast.text.contains("(2)"),
"toast names the projected cell count, got {:?}",
toast.text
);
}
+13 -1
View File
@@ -3655,7 +3655,19 @@ fn mouse_selection_autocopies_on_release_without_ctrl_c() {
},
);
assert_eq!(app.status_message.as_deref(), Some("Selection copied"));
// Drag-release autocopy now takes the Markdown-source path (#6156): the
// clipboard holds canonical cell content and the receipt is a toast
// naming the projected cell count, not the legacy status sink.
assert!(
app.status_message.is_none(),
"markdown copy must not touch the legacy status sink"
);
let toast = app.status_toasts.back().expect("markdown copy toast");
assert!(
toast.text.contains("(1)"),
"toast names the projected cell count, got {:?}",
toast.text
);
assert!(
app.clipboard
.last_written_text()