Files
telegram-tui/tests/chat_list.rs
Mikhail Kilin 8e48d076de refactor: implement trait-based DI for TdClient and fix stack overflow
Implement complete trait-based dependency injection pattern for TdClient
to enable testing with FakeTdClient mock. Fix critical stack overflow bugs
caused by infinite recursion in trait implementations.

Breaking Changes:
- App is now generic: App<T: TdClientTrait = TdClient>
- All UI and input handlers are generic over TdClientTrait
- TdClient methods now accessed through trait interface

New Files:
- src/tdlib/trait.rs: TdClientTrait definition with 40+ methods
- src/tdlib/client_impl.rs: TdClientTrait impl for TdClient
- tests/helpers/fake_tdclient_impl.rs: TdClientTrait impl for FakeTdClient

Critical Fixes:
- Fix stack overflow in send_message, edit_message, delete_messages
- Fix stack overflow in forward_messages, current_chat_messages
- Fix stack overflow in current_pinned_message
- All methods now call message_manager directly to avoid recursion

Testing:
- FakeTdClient supports configurable auth_state for auth screen tests
- Added pinned message support in FakeTdClient
- All 196+ tests passing (188 tests + 8 benchmarks)

Dependencies:
- Added async-trait = "0.1"

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 05:42:19 +03:00

188 lines
5.1 KiB
Rust

// Chat list UI snapshot tests
mod helpers;
use helpers::app_builder::TestAppBuilder;
use helpers::snapshot_utils::{buffer_to_string, render_to_buffer};
use helpers::test_data::{create_test_chat, TestChatBuilder};
use insta::assert_snapshot;
#[test]
fn snapshot_empty_chat_list() {
let mut app = TestAppBuilder::new().build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("empty_chat_list", output);
}
#[test]
fn snapshot_chat_list_with_three_chats() {
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Boss", 456);
let chat3 = create_test_chat("Rust Community", 789);
let mut app = TestAppBuilder::new()
.with_chats(vec![chat1, chat2, chat3])
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_list_three_chats", output);
}
#[test]
fn snapshot_chat_with_unread_count() {
let chat = TestChatBuilder::new("Mom", 123)
.unread_count(5)
.last_message("Привет, как дела?")
.build();
let mut app = TestAppBuilder::new().with_chat(chat).build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_with_unread", output);
}
#[test]
fn snapshot_chat_with_pinned() {
let chat = TestChatBuilder::new("Important Chat", 123)
.pinned()
.last_message("Pinned message")
.build();
let mut app = TestAppBuilder::new().with_chat(chat).build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_pinned", output);
}
#[test]
fn snapshot_chat_with_muted() {
let chat = TestChatBuilder::new("Spam Group", 123)
.muted()
.unread_count(99)
.last_message("Too many messages")
.build();
let mut app = TestAppBuilder::new().with_chat(chat).build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_muted", output);
}
#[test]
fn snapshot_chat_with_mentions() {
let chat = TestChatBuilder::new("Work Group", 123)
.unread_count(10)
.unread_mentions(2)
.last_message("@me check this out")
.build();
let mut app = TestAppBuilder::new().with_chat(chat).build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_with_mentions", output);
}
#[test]
fn snapshot_selected_chat() {
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Boss", 456);
let mut app = TestAppBuilder::new()
.with_chats(vec![chat1, chat2])
.selected_chat(123)
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_selected", output);
}
#[test]
fn snapshot_chat_long_title() {
let chat = TestChatBuilder::new("Very Long Chat Title That Should Be Truncated", 123)
.last_message("Test message")
.build();
let mut app = TestAppBuilder::new().with_chat(chat).build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_long_title", output);
}
#[test]
fn snapshot_chat_search_mode() {
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Boss", 456);
let chat3 = create_test_chat("Rust Community", 789);
let mut app = TestAppBuilder::new()
.with_chats(vec![chat1, chat2, chat3])
.searching("Mom")
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_list_search_mode", output);
}
#[test]
fn snapshot_chat_with_online_status() {
use tele_tui::tdlib::UserOnlineStatus;
use tele_tui::types::ChatId;
let chat = TestChatBuilder::new("Alice", 123)
.last_message("Hey there!")
.build();
let mut app = TestAppBuilder::new()
.with_chat(chat)
.selected_chat(123)
.build();
// Note: Online status setup removed due to trait-based DI
// User status is not critical for this UI snapshot test
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("chat_with_online_status", output);
}