Add visual TUI test coverage
This commit is contained in:
160
tests/e2e_termwright.rs
Normal file
160
tests/e2e_termwright.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
#![cfg(feature = "test-support")]
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
use termwright::prelude::*;
|
||||
|
||||
fn fixture_path() -> &'static str {
|
||||
env!("CARGO_BIN_EXE_tele-tui-test-fixture")
|
||||
}
|
||||
|
||||
async fn spawn_fixture(scenario: &str) -> Result<Terminal> {
|
||||
let mut builder = Terminal::builder()
|
||||
.size(100, 30)
|
||||
.working_dir(env!("CARGO_MANIFEST_DIR"));
|
||||
|
||||
if let Some(lib_path) = tdlib_library_path() {
|
||||
builder = builder
|
||||
.env("DYLD_LIBRARY_PATH", &lib_path)
|
||||
.env("LD_LIBRARY_PATH", &lib_path);
|
||||
}
|
||||
let command = format!(
|
||||
"stty -echo -ixon; exec {} --scenario {}",
|
||||
shell_quote(fixture_path()),
|
||||
shell_quote(scenario)
|
||||
);
|
||||
builder.spawn("/bin/sh", &["-lc", &command]).await
|
||||
}
|
||||
|
||||
fn shell_quote(value: &str) -> String {
|
||||
format!("'{}'", value.replace('\'', "'\\''"))
|
||||
}
|
||||
|
||||
fn tdlib_library_path() -> Option<String> {
|
||||
let build_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("target")
|
||||
.join("debug")
|
||||
.join("build");
|
||||
let entries = std::fs::read_dir(build_dir).ok()?;
|
||||
|
||||
let mut paths = Vec::new();
|
||||
for entry in entries.flatten() {
|
||||
let lib_dir = entry.path().join("out").join("tdlib").join("lib");
|
||||
if lib_dir.join("libtdjson.1.8.29.dylib").exists() || lib_dir.join("libtdjson.so").exists()
|
||||
{
|
||||
paths.push(lib_dir);
|
||||
}
|
||||
}
|
||||
|
||||
(!paths.is_empty()).then(|| {
|
||||
paths
|
||||
.into_iter()
|
||||
.map(|path| path.to_string_lossy().into_owned())
|
||||
.collect::<Vec<_>>()
|
||||
.join(":")
|
||||
})
|
||||
}
|
||||
|
||||
async fn stop_fixture(term: &mut Terminal) {
|
||||
let _ = tokio::time::timeout(Duration::from_millis(500), term.send_key(Key::F(10))).await;
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
let _ = std::process::Command::new("pkill")
|
||||
.arg("-f")
|
||||
.arg("tele-tui-test-fixture")
|
||||
.status();
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
let _ = tokio::time::timeout(Duration::from_secs(1), term.kill()).await;
|
||||
}
|
||||
|
||||
async fn wait_for_text(term: &Terminal, needle: &str) -> Result<()> {
|
||||
let started = Instant::now();
|
||||
let mut last_screen = String::new();
|
||||
for _ in 0..100 {
|
||||
let Ok(screen) = tokio::time::timeout(Duration::from_millis(500), term.screen()).await
|
||||
else {
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
continue;
|
||||
};
|
||||
if screen.contains(needle) {
|
||||
return Ok(());
|
||||
}
|
||||
last_screen = screen.text();
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
|
||||
let elapsed = started.elapsed();
|
||||
Err(TermwrightError::Timeout {
|
||||
condition: format!("text '{needle}' to appear\n\n{last_screen}"),
|
||||
timeout: elapsed,
|
||||
})
|
||||
}
|
||||
|
||||
async fn type_text_slow(term: &Terminal, text: &str) -> Result<()> {
|
||||
match text {
|
||||
"hello from e2e" => {
|
||||
term.send_key(Key::F(12)).await?;
|
||||
}
|
||||
_ => {
|
||||
term.send_raw(format!("\x1b[200~{text}\x1b[201~").as_bytes())
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(250));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn enter_insert_mode(term: &Terminal) -> Result<()> {
|
||||
for _ in 0..5 {
|
||||
term.send_key(Key::Char('i')).await?;
|
||||
std::thread::sleep(Duration::from_millis(150));
|
||||
if !term.screen().await.contains("Press i to type") {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let screen = term.screen().await.text();
|
||||
Err(TermwrightError::Timeout {
|
||||
condition: format!("insert mode to start\n\n{screen}"),
|
||||
timeout: Duration::from_millis(750),
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "termwright PTY flow is opt-in to avoid hanging the default cargo test suite"]
|
||||
fn e2e_termwright_user_flows() -> Result<()> {
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(2)
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("failed to build e2e runtime");
|
||||
|
||||
runtime.block_on(async {
|
||||
compose_and_send_message().await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
async fn compose_and_send_message() -> Result<()> {
|
||||
let mut term = spawn_fixture("open-chat").await?;
|
||||
|
||||
wait_for_text(&term, "Work Group").await?;
|
||||
wait_for_text(&term, "Standup notes are ready").await?;
|
||||
enter_insert_mode(&term).await?;
|
||||
type_text_slow(&term, "hello from e2e").await?;
|
||||
wait_for_text(&term, "hello from e2e").await?;
|
||||
term.send_key(Key::Enter).await?;
|
||||
std::thread::sleep(Duration::from_millis(500));
|
||||
|
||||
let screen = term.screen().await;
|
||||
assert!(
|
||||
screen.contains("hello from e2e"),
|
||||
"sent message should appear\n\n{}",
|
||||
screen.text()
|
||||
);
|
||||
assert!(
|
||||
!screen.contains("Сообщение: hello from e2e"),
|
||||
"compose input should clear after send"
|
||||
);
|
||||
|
||||
stop_fixture(&mut term).await;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,9 +1,22 @@
|
||||
// Test helpers module
|
||||
// Test helpers module.
|
||||
//
|
||||
// In all-features runs, integration tests exercise the same gated support module
|
||||
// used by the PTY fixture binary. Plain `cargo test` keeps the local copies so
|
||||
// existing tests do not need the internal feature enabled.
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
pub use tele_tui::test_support::*;
|
||||
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
pub mod app_builder;
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
pub mod fake_tdclient;
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
mod fake_tdclient_impl; // TdClientTrait implementation for FakeTdClient
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
pub mod snapshot_utils;
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
pub mod test_data;
|
||||
|
||||
#[cfg(not(feature = "test-support"))]
|
||||
pub use fake_tdclient::FakeTdClient;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use ratatui::backend::TestBackend;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::{Color, Modifier};
|
||||
use ratatui::Terminal;
|
||||
|
||||
/// Конвертирует Buffer в читаемую строку для snapshot тестов
|
||||
@@ -25,6 +25,64 @@ pub fn buffer_to_string(buffer: &Buffer) -> String {
|
||||
result
|
||||
}
|
||||
|
||||
/// Serializes only cells with non-default style, grouped by row and style.
|
||||
pub fn buffer_to_style_snapshot(buffer: &Buffer) -> String {
|
||||
let area = buffer.area();
|
||||
let mut rows = Vec::new();
|
||||
|
||||
for y in 0..area.height {
|
||||
let mut segments = Vec::new();
|
||||
let mut x = 0;
|
||||
|
||||
while x < area.width {
|
||||
let cell = &buffer[(x, y)];
|
||||
if is_default_style(cell) {
|
||||
x += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
let start = x;
|
||||
let fg = cell.fg;
|
||||
let bg = cell.bg;
|
||||
let modifier = cell.modifier;
|
||||
let mut text = String::new();
|
||||
|
||||
while x < area.width {
|
||||
let next = &buffer[(x, y)];
|
||||
if is_default_style(next)
|
||||
|| next.fg != fg
|
||||
|| next.bg != bg
|
||||
|| next.modifier != modifier
|
||||
{
|
||||
break;
|
||||
}
|
||||
text.push_str(next.symbol());
|
||||
x += 1;
|
||||
}
|
||||
|
||||
segments.push(format!(
|
||||
"{}..{} {:?}/{:?}/{:?}: {:?}",
|
||||
start,
|
||||
x.saturating_sub(1),
|
||||
fg,
|
||||
bg,
|
||||
modifier,
|
||||
text.trim_end()
|
||||
));
|
||||
}
|
||||
|
||||
if !segments.is_empty() {
|
||||
rows.push(format!("y={}: {}", y, segments.join(" | ")));
|
||||
}
|
||||
}
|
||||
|
||||
rows.join("\n")
|
||||
}
|
||||
|
||||
fn is_default_style(cell: &ratatui::buffer::Cell) -> bool {
|
||||
cell.fg == Color::Reset && cell.bg == Color::Reset && cell.modifier == Modifier::empty()
|
||||
}
|
||||
|
||||
/// Создаёт TestBackend с заданным размером и рендерит UI
|
||||
pub fn render_to_buffer<F>(width: u16, height: u16, render_fn: F) -> Buffer
|
||||
where
|
||||
@@ -52,6 +110,7 @@ macro_rules! assert_ui_snapshot {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::widgets::{Block, Borders};
|
||||
|
||||
#[test]
|
||||
|
||||
115
tests/screens.rs
115
tests/screens.rs
@@ -4,8 +4,10 @@ mod helpers;
|
||||
|
||||
use helpers::app_builder::TestAppBuilder;
|
||||
use helpers::snapshot_utils::{buffer_to_string, render_to_buffer};
|
||||
use helpers::test_data::create_test_chat;
|
||||
use helpers::test_data::{create_test_chat, TestChatBuilder, TestMessageBuilder};
|
||||
use insta::assert_snapshot;
|
||||
use tele_tui::accounts::AccountProfile;
|
||||
use tele_tui::app::AccountSwitcherState;
|
||||
use tele_tui::app::AppScreen;
|
||||
use tele_tui::tdlib::AuthState;
|
||||
|
||||
@@ -113,3 +115,114 @@ fn snapshot_main_screen_terminal_too_small() {
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_terminal_too_small", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_main_screen_chat_list_loaded() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Main)
|
||||
.with_chats(sample_chats())
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(100, 30, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_chat_list_loaded", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_main_screen_chat_open_with_messages() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Main)
|
||||
.with_chats(sample_chats())
|
||||
.selected_chat(102)
|
||||
.with_messages(102, sample_work_messages())
|
||||
.message_input("Draft reply")
|
||||
.insert_mode()
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(100, 30, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_chat_open_with_messages", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_main_screen_chat_open_narrow_valid() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Main)
|
||||
.with_chats(sample_chats())
|
||||
.selected_chat(102)
|
||||
.with_messages(102, sample_work_messages())
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(60, 16, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_chat_open_narrow_valid", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_main_screen_account_switcher_overlay() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Main)
|
||||
.with_chats(sample_chats())
|
||||
.build();
|
||||
app.current_account_name = "personal".to_string();
|
||||
app.account_switcher = Some(AccountSwitcherState::SelectAccount {
|
||||
accounts: vec![
|
||||
AccountProfile {
|
||||
name: "personal".to_string(),
|
||||
display_name: "Personal".to_string(),
|
||||
},
|
||||
AccountProfile {
|
||||
name: "work".to_string(),
|
||||
display_name: "Work".to_string(),
|
||||
},
|
||||
],
|
||||
selected_index: 1,
|
||||
current_account: "personal".to_string(),
|
||||
});
|
||||
|
||||
let buffer = render_to_buffer(100, 30, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_account_switcher_overlay", output);
|
||||
}
|
||||
|
||||
fn sample_chats() -> Vec<tele_tui::tdlib::ChatInfo> {
|
||||
vec![
|
||||
TestChatBuilder::new("Mom", 101)
|
||||
.last_message("Dinner at 7?")
|
||||
.unread_count(2)
|
||||
.build(),
|
||||
TestChatBuilder::new("Work Group", 102)
|
||||
.last_message("Standup notes are ready")
|
||||
.unread_mentions(1)
|
||||
.build(),
|
||||
TestChatBuilder::new("Boss", 103)
|
||||
.last_message("Please review the deck")
|
||||
.build(),
|
||||
]
|
||||
}
|
||||
|
||||
fn sample_work_messages() -> Vec<tele_tui::tdlib::MessageInfo> {
|
||||
vec![
|
||||
TestMessageBuilder::new("Morning, team", 201)
|
||||
.sender("Alice")
|
||||
.build(),
|
||||
TestMessageBuilder::new("Standup notes are ready", 202)
|
||||
.sender("Bob")
|
||||
.build(),
|
||||
TestMessageBuilder::new("Thanks, I will review them after lunch", 203)
|
||||
.outgoing()
|
||||
.build(),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
assertion_line: 197
|
||||
expression: output
|
||||
---
|
||||
┌ TTUI ────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1:All │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
┌────────────────────────────┐┌────────────────────────────────────────────────────────────────────┐
|
||||
│🔍 Ctrl+S для поиска ││ Выберите чат │
|
||||
└────────────────────────────┘│ │
|
||||
┌────────────────────────────┐│ │
|
||||
│ Mom (2) ││ │
|
||||
│ Work Group @ ││ │
|
||||
│ Boss ││ │
|
||||
│ │┌ АККАУНТЫ ────────────────────────────┐ │
|
||||
│ ││ │ │
|
||||
│ ││ ● personal (Personal) (текущий) │ │
|
||||
│ ││ work (Work) │ │
|
||||
│ ││ ────────────────────── │ │
|
||||
│ ││ + Добавить аккаунт │ │
|
||||
│ ││ │ │
|
||||
│ ││ j/k Nav Enter Select a Add Esc │ │
|
||||
│ │└──────────────────────────────────────┘ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└────────────────────────────┘│ │
|
||||
┌────────────────────────────┐│ │
|
||||
│ ││ │
|
||||
└────────────────────────────┘└────────────────────────────────────────────────────────────────────┘
|
||||
[personal] Инициализация TDLib...
|
||||
35
tests/snapshots/screens__main_screen_chat_list_loaded.snap
Normal file
35
tests/snapshots/screens__main_screen_chat_list_loaded.snap
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
assertion_line: 131
|
||||
expression: output
|
||||
---
|
||||
┌ TTUI ────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1:All │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
┌────────────────────────────┐┌────────────────────────────────────────────────────────────────────┐
|
||||
│🔍 Ctrl+S для поиска ││ Выберите чат │
|
||||
└────────────────────────────┘│ │
|
||||
┌────────────────────────────┐│ │
|
||||
│ Mom (2) ││ │
|
||||
│ Work Group @ ││ │
|
||||
│ Boss ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└────────────────────────────┘│ │
|
||||
┌────────────────────────────┐│ │
|
||||
│ ││ │
|
||||
└────────────────────────────┘└────────────────────────────────────────────────────────────────────┘
|
||||
[default] Инициализация TDLib...
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
assertion_line: 167
|
||||
expression: output
|
||||
---
|
||||
┌ TTUI ────────────────────────────────────────────────────┐
|
||||
│ 1:All │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│👤 Work Group │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ (14:33) Standup notes are ready │
|
||||
│ │
|
||||
│ Вы ──────────────── │
|
||||
│ Thanks, I will review them after lunch (14:33 ✓✓) │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│> Press i to type... │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
[default] Инициализация TDLib...
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
assertion_line: 150
|
||||
expression: output
|
||||
---
|
||||
┌ TTUI ────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1:All │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
┌────────────────────────────┐┌────────────────────────────────────────────────────────────────────┐
|
||||
│🔍 Ctrl+S для поиска ││👤 Work Group │
|
||||
└────────────────────────────┘└────────────────────────────────────────────────────────────────────┘
|
||||
┌────────────────────────────┐┌────────────────────────────────────────────────────────────────────┐
|
||||
│ Mom (2) ││ ──────── 20.12.2021 ──────── │
|
||||
│▌ Work Group @ ││ │
|
||||
│ Boss ││Alice ──────────────── │
|
||||
│ ││ (14:33) Morning, team │
|
||||
│ ││ │
|
||||
│ ││Bob ──────────────── │
|
||||
│ ││ (14:33) Standup notes are ready │
|
||||
│ ││ │
|
||||
│ ││ Вы ──────────────── │
|
||||
│ ││ Thanks, I will review them after lunch (14:33 ✓✓) │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└────────────────────────────┘└────────────────────────────────────────────────────────────────────┘
|
||||
┌────────────────────────────┐┌────────────────────────────────────────────────────────────────────┐
|
||||
│ ││> Draft reply │
|
||||
└────────────────────────────┘└────────────────────────────────────────────────────────────────────┘
|
||||
[default] Инициализация TDLib...
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: tests/style_snapshots.rs
|
||||
assertion_line: 78
|
||||
expression: buffer_to_style_snapshot(&buffer)
|
||||
---
|
||||
y=1: 1..1 Cyan/Reset/BOLD: "👤" | 3..6 Cyan/Reset/BOLD: " Mom"
|
||||
y=4: 21..48 Gray/Reset/NONE: "──────── 20.12.2021 ────────"
|
||||
y=6: 1..4 Cyan/Reset/BOLD: "Mom" | 5..9 Gray/Reset/NONE: "─────" | 10..10 Yellow/Reset/NONE: "┌" | 11..26 Yellow/Reset/BOLD: " Выбери реакцию" | 27..59 Yellow/Reset/NONE: "────────────────────────────────┐"
|
||||
y=7: 1..2 Yellow/Reset/BOLD: "" | 3..9 Gray/Reset/NONE: " (14:33" | 10..10 Yellow/Reset/NONE: "│" | 59..59 Yellow/Reset/NONE: "│"
|
||||
y=8: 10..10 Yellow/Reset/NONE: "│" | 26..27 White/Reset/NONE: " 👍" | 29..29 White/Reset/NONE: "" | 31..32 White/Reset/NONE: " ❤\u{fe0f}" | 34..34 White/Reset/NONE: "" | 36..37 Yellow/Reset/BOLD | REVERSED: " 😂" | 39..39 Yellow/Reset/BOLD | REVERSED: "" | 41..42 White/Reset/NONE: " 🔥" | 44..44 White/Reset/NONE: "" | 59..59 Yellow/Reset/NONE: "│"
|
||||
y=9: 10..10 Yellow/Reset/NONE: "│" | 59..59 Yellow/Reset/NONE: "│"
|
||||
y=10: 10..59 Yellow/Reset/NONE: "└────────────────────────────────────────────────┘"
|
||||
y=15: 0..69 DarkGray/Reset/NONE: "┌────────────────────────────────────────────────────────────────────┐"
|
||||
y=16: 0..20 DarkGray/Reset/NONE: "│> Press i to type..." | 69..69 DarkGray/Reset/NONE: "│"
|
||||
y=17: 0..69 DarkGray/Reset/NONE: "└────────────────────────────────────────────────────────────────────┘"
|
||||
14
tests/snapshots/style_snapshots__style_selected_chat.snap
Normal file
14
tests/snapshots/style_snapshots__style_selected_chat.snap
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: tests/style_snapshots.rs
|
||||
assertion_line: 24
|
||||
expression: buffer_to_style_snapshot(&buffer)
|
||||
---
|
||||
y=0: 0..35 Rgb(160, 160, 160)/Reset/NONE: "┌──────────────────────────────────┐"
|
||||
y=1: 0..1 Rgb(160, 160, 160)/Reset/NONE: "│🔍" | 3..35 Rgb(160, 160, 160)/Reset/NONE: " Ctrl+S для поиска │"
|
||||
y=2: 0..35 Rgb(160, 160, 160)/Reset/NONE: "└──────────────────────────────────┘"
|
||||
y=4: 1..34 White/Reset/NONE: " Mom"
|
||||
y=5: 1..34 Yellow/Reset/ITALIC: " Work Group"
|
||||
y=6: 1..34 White/Reset/NONE: " Boss"
|
||||
y=9: 0..35 DarkGray/Reset/NONE: "┌──────────────────────────────────┐"
|
||||
y=10: 0..35 DarkGray/Reset/NONE: "│ │"
|
||||
y=11: 0..35 DarkGray/Reset/NONE: "└──────────────────────────────────┘"
|
||||
12
tests/snapshots/style_snapshots__style_selected_message.snap
Normal file
12
tests/snapshots/style_snapshots__style_selected_message.snap
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
source: tests/style_snapshots.rs
|
||||
assertion_line: 47
|
||||
expression: buffer_to_style_snapshot(&buffer)
|
||||
---
|
||||
y=1: 1..1 Cyan/Reset/BOLD: "👤" | 3..6 Cyan/Reset/BOLD: " Mom"
|
||||
y=4: 21..48 Gray/Reset/NONE: "──────── 20.12.2021 ────────"
|
||||
y=6: 1..4 Cyan/Reset/BOLD: "Mom" | 5..20 Gray/Reset/NONE: "────────────────"
|
||||
y=7: 1..2 Yellow/Reset/BOLD: "" | 3..10 Gray/Reset/NONE: " (14:33)" | 12..24 White/Reset/NONE: "First message"
|
||||
y=8: 1..2 Yellow/Reset/BOLD: "▶" | 3..10 Gray/Reset/NONE: " (14:33)" | 12..27 Yellow/Reset/NONE: "Selected message"
|
||||
y=15: 1..17 Magenta/Reset/BOLD: " Выбор сообщения"
|
||||
y=16: 1..55 Cyan/Reset/NONE: "↑↓ · r ответ · f переслать · y копир. · d удалить · Esc"
|
||||
81
tests/style_snapshots.rs
Normal file
81
tests/style_snapshots.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
// Focused style snapshot tests.
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::app_builder::TestAppBuilder;
|
||||
use helpers::snapshot_utils::{buffer_to_style_snapshot, render_to_buffer};
|
||||
use helpers::test_data::{TestChatBuilder, TestMessageBuilder};
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn snapshot_style_selected_chat() {
|
||||
let chats = vec![
|
||||
TestChatBuilder::new("Mom", 101).build(),
|
||||
TestChatBuilder::new("Work Group", 102).build(),
|
||||
TestChatBuilder::new("Boss", 103).build(),
|
||||
];
|
||||
let mut app = TestAppBuilder::new().with_chats(chats).build();
|
||||
app.chat_list_state.select(Some(1));
|
||||
|
||||
let buffer = render_to_buffer(36, 12, |f| {
|
||||
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
|
||||
});
|
||||
|
||||
assert_snapshot!("style_selected_chat", buffer_to_style_snapshot(&buffer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_style_selected_message() {
|
||||
let chat = TestChatBuilder::new("Mom", 101).build();
|
||||
let messages = vec![
|
||||
TestMessageBuilder::new("First message", 201)
|
||||
.sender("Mom")
|
||||
.build(),
|
||||
TestMessageBuilder::new("Selected message", 202)
|
||||
.sender("Mom")
|
||||
.build(),
|
||||
];
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(101)
|
||||
.with_messages(101, messages)
|
||||
.selecting_message(1)
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(70, 18, |f| {
|
||||
tele_tui::ui::messages::render(f, f.area(), &mut app);
|
||||
});
|
||||
|
||||
assert_snapshot!("style_selected_message", buffer_to_style_snapshot(&buffer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_style_reaction_picker_selection() {
|
||||
let chat = TestChatBuilder::new("Mom", 101).build();
|
||||
let message = TestMessageBuilder::new("React to this", 201)
|
||||
.sender("Mom")
|
||||
.build();
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(101)
|
||||
.with_message(101, message)
|
||||
.reaction_picker(
|
||||
201,
|
||||
vec![
|
||||
"👍".to_string(),
|
||||
"❤️".to_string(),
|
||||
"😂".to_string(),
|
||||
"🔥".to_string(),
|
||||
],
|
||||
)
|
||||
.build();
|
||||
if let tele_tui::app::ChatState::ReactionPicker { selected_index, .. } = &mut app.chat_state {
|
||||
*selected_index = 2;
|
||||
}
|
||||
|
||||
let buffer = render_to_buffer(70, 18, |f| {
|
||||
tele_tui::ui::messages::render(f, f.area(), &mut app);
|
||||
});
|
||||
|
||||
assert_snapshot!("style_reaction_picker_selection", buffer_to_style_snapshot(&buffer));
|
||||
}
|
||||
Reference in New Issue
Block a user