Files
telegram-tui/tests/modals.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

199 lines
6.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Modals UI snapshot tests
mod helpers;
use helpers::app_builder::TestAppBuilder;
use tele_tui::tdlib::TdClientTrait;
use helpers::snapshot_utils::{buffer_to_string, render_to_buffer};
use helpers::test_data::{
create_test_chat, create_test_profile, TestChatBuilder, TestMessageBuilder,
};
use insta::assert_snapshot;
#[test]
fn snapshot_delete_confirmation_modal() {
let chat = create_test_chat("Mom", 123);
let message = TestMessageBuilder::new("Delete me", 1).outgoing().build();
let app = TestAppBuilder::new()
.with_chat(chat)
.with_message(123, message)
.selected_chat(123)
.delete_confirmation(1)
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("delete_confirmation_modal", output);
}
#[test]
fn snapshot_emoji_picker_default() {
let chat = create_test_chat("Mom", 123);
let message = TestMessageBuilder::new("React to this", 1).build();
let reactions = vec!["👍".to_string(), "👎".to_string(), "❤️".to_string(), "🔥".to_string(), "😊".to_string(), "😢".to_string(), "😮".to_string(), "🎉".to_string()];
let app = TestAppBuilder::new()
.with_chat(chat)
.with_message(123, message)
.selected_chat(123)
.reaction_picker(1, reactions)
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("emoji_picker_default", output);
}
#[test]
fn snapshot_emoji_picker_with_selection() {
let chat = create_test_chat("Mom", 123);
let message = TestMessageBuilder::new("React to this", 1).build();
let reactions = vec!["👍".to_string(), "👎".to_string(), "❤️".to_string(), "🔥".to_string(), "😊".to_string(), "😢".to_string(), "😮".to_string(), "🎉".to_string()];
let mut app = TestAppBuilder::new()
.with_chat(chat)
.with_message(123, message)
.selected_chat(123)
.reaction_picker(1, reactions)
.build();
// Выбираем 5-ю реакцию (индекс 4)
if let tele_tui::app::ChatState::ReactionPicker { selected_index, .. } = &mut app.chat_state {
*selected_index = 4;
}
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("emoji_picker_with_selection", output);
}
#[test]
fn snapshot_profile_personal_chat() {
let chat = create_test_chat("Alice", 123);
let profile = create_test_profile("Alice", 123);
let app = TestAppBuilder::new()
.with_chat(chat)
.selected_chat(123)
.profile_mode(profile)
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("profile_personal_chat", output);
}
#[test]
fn snapshot_profile_group_chat() {
let chat = TestChatBuilder::new("Work Group", 456).build();
let mut profile = create_test_profile("Work Group", 456);
profile.is_group = true;
profile.chat_type = "Группа".to_string();
profile.member_count = Some(25);
profile.description = Some("Work discussion group".to_string());
let app = TestAppBuilder::new()
.with_chat(chat)
.selected_chat(456)
.profile_mode(profile)
.build();
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("profile_group_chat", output);
}
#[test]
fn snapshot_pinned_message() {
let chat = create_test_chat("Mom", 123);
let message1 = TestMessageBuilder::new("Regular message", 1).build();
let pinned_msg = TestMessageBuilder::new("Important pinned message!", 2).build();
let mut app = TestAppBuilder::new()
.with_chat(chat)
.with_messages(123, vec![message1])
.selected_chat(123)
.build();
// Устанавливаем закреплённое сообщение
app.td_client.set_current_pinned_message(Some(pinned_msg));
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("pinned_message", output);
}
#[test]
fn snapshot_search_in_chat() {
let chat = create_test_chat("Mom", 123);
let msg1 = TestMessageBuilder::new("Hello world", 1).build();
let msg2 = TestMessageBuilder::new("World is beautiful", 2).build();
let msg3 = TestMessageBuilder::new("Beautiful day", 3).build();
let mut app = TestAppBuilder::new()
.with_chat(chat)
.with_messages(123, vec![msg1.clone(), msg2.clone(), msg3])
.selected_chat(123)
.message_search("world")
.build();
// Устанавливаем результаты поиска
if let tele_tui::app::ChatState::SearchInChat { results, selected_index, .. } = &mut app.chat_state {
*results = vec![msg1, msg2];
*selected_index = 0;
}
let buffer = render_to_buffer(80, 24, |f| {
tele_tui::ui::messages::render(f, f.area(), &app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("search_in_chat", output);
}
#[test]
fn snapshot_forward_mode() {
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Dad", 456);
let chat3 = create_test_chat("Work Group", 789);
let message = TestMessageBuilder::new("Forward this message", 1).build();
let mut app = TestAppBuilder::new()
.with_chats(vec![chat1.clone(), chat2, chat3])
.with_message(123, message)
.selected_chat(123)
.forward_mode(1)
.build();
let buffer = render_to_buffer(80, 24, |f| {
// В forward mode показывается chat_list для выбора чата
tele_tui::ui::chat_list::render(f, f.area(), &mut app);
});
let output = buffer_to_string(&buffer);
assert_snapshot!("forward_mode", output);
}