From bfc92231496fa636528579d697965dda63d0e87f Mon Sep 17 00:00:00 2001 From: Felipe Coury Date: Wed, 29 Apr 2026 11:53:00 -0300 Subject: [PATCH] test(tui): cover streaming markdown tables --- ...t__tests__streaming_table_tail_active.snap | 8 +++ .../src/chatwidget/tests/status_and_layout.rs | 34 ++++++++++++ codex-rs/tui/src/markdown_render_tests.rs | 54 +++++++++++++++++++ ...sts__markdown_render_complex_snapshot.snap | 10 ++-- 4 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__streaming_table_tail_active.snap diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__streaming_table_tail_active.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__streaming_table_tail_active.snap new file mode 100644 index 0000000000..bad62d1247 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__streaming_table_tail_active.snap @@ -0,0 +1,8 @@ +--- +source: tui/src/chatwidget/tests/status_and_layout.rs +expression: active_blob(&chat) +--- +• ┌──────┬───────┐ + │ Name │ Value │ + ├──────┼───────┤ + └──────┴───────┘ diff --git a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs index c71c57dfef..fe61d84356 100644 --- a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs +++ b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs @@ -928,6 +928,40 @@ async fn streaming_final_answer_keeps_task_running_state() { assert!(!chat.bottom_pane.quit_shortcut_hint_visible()); } +#[tokio::test] +async fn streaming_markdown_tail_updates_in_place_until_next_block_stabilizes_it() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + + chat.on_task_started(); + chat.on_agent_message_delta("First paragraph\n".to_string()); + assert_eq!(drain_insert_history(&mut rx).len(), 0); + assert_eq!(active_blob(&chat), "• First paragraph\n"); + + chat.on_agent_message_delta("\nSecond paragraph\n".to_string()); + chat.on_commit_tick(); + let inserted = drain_insert_history(&mut rx); + assert_eq!(inserted.len(), 1); + assert_eq!(lines_to_single_string(&inserted[0]), "• First paragraph\n"); + assert_eq!(active_blob(&chat), " \n Second paragraph\n"); +} + +#[tokio::test] +async fn streaming_table_tail_renders_from_complete_lines_only() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + + chat.on_task_started(); + chat.on_agent_message_delta("| Name | Value |\n".to_string()); + assert_eq!(drain_insert_history(&mut rx).len(), 0); + assert_eq!(active_blob(&chat), "• | Name | Value |\n"); + + chat.on_agent_message_delta("| --- | --- |\n".to_string()); + assert_eq!(drain_insert_history(&mut rx).len(), 0); + assert_chatwidget_snapshot!("streaming_table_tail_active", active_blob(&chat)); + + chat.on_agent_message_delta("| A | 1 |".to_string()); + assert_chatwidget_snapshot!("streaming_table_tail_active", active_blob(&chat)); +} + #[tokio::test] async fn idle_commit_ticks_do_not_restore_status_without_commentary_completion() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; diff --git a/codex-rs/tui/src/markdown_render_tests.rs b/codex-rs/tui/src/markdown_render_tests.rs index cb15c5ff70..7719518bee 100644 --- a/codex-rs/tui/src/markdown_render_tests.rs +++ b/codex-rs/tui/src/markdown_render_tests.rs @@ -56,6 +56,59 @@ fn paragraph_multiple() { ); } +#[test] +fn table_renders_as_box() { + let text = render_markdown_text("| Name | Value |\n| --- | --- |\n| A | 1 |\n"); + + assert_eq!( + plain_lines(&text), + vec![ + "┌──────┬───────┐", + "│ Name │ Value │", + "├──────┼───────┤", + "│ A │ 1 │", + "└──────┴───────┘", + ], + ); +} + +#[test] +fn table_respects_column_alignment() { + let text = render_markdown_text("| Left | Center | Right |\n| :--- | :---: | ---: |\n| a | b | c |\n"); + + assert_eq!( + plain_lines(&text), + vec![ + "┌──────┬────────┬───────┐", + "│ Left │ Center │ Right │", + "├──────┼────────┼───────┤", + "│ a │ b │ c │", + "└──────┴────────┴───────┘", + ], + ); +} + +#[test] +fn narrow_table_stays_boxed_even_when_it_overflows() { + let text = render_markdown_text_with_width_and_cwd( + "| Name | Description |\n| --- | --- |\n| Alpha | a value that wraps |\n", + Some(20), + /*cwd*/ None, + ); + + assert_eq!( + plain_lines(&text), + vec![ + "┌───────┬─────────────┐", + "│ Name │ Description │", + "├───────┼─────────────┤", + "│ Alpha │ a value │", + "│ │ that wraps │", + "└───────┴─────────────┘", + ], + ); +} + #[test] fn headings() { let md = "# Heading 1\n## Heading 2\n### Heading 3\n#### Heading 4\n##### Heading 5\n###### Heading 6\n"; @@ -1203,6 +1256,7 @@ Table below (alignment test): | Left | Center | Right | |:-----|:------:|------:| | a | b | c | + Inline HTML: sup and sub. HTML block:
inline block
diff --git a/codex-rs/tui/src/snapshots/codex_tui__markdown_render__markdown_render_tests__markdown_render_complex_snapshot.snap b/codex-rs/tui/src/snapshots/codex_tui__markdown_render__markdown_render_tests__markdown_render_complex_snapshot.snap index cc752dd66d..a838e0955f 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__markdown_render__markdown_render_tests__markdown_render_complex_snapshot.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__markdown_render__markdown_render_tests__markdown_render_complex_snapshot.snap @@ -28,9 +28,13 @@ Image: alt text ——— Table below (alignment test): -| Left | Center | Right | -|:-----|:------:|------:| -| a | b | c | + +┌──────┬────────┬───────┐ +│ Left │ Center │ Right │ +├──────┼────────┼───────┤ +│ a │ b │ c │ +└──────┴────────┴───────┘ + Inline HTML: sup and sub. HTML block:
inline block