Files
telegram-tui/tests/e2e_user_journey.rs
Mikhail Kilin 2b04b785c0
Some checks failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled
refactor: cleanup unused code and warnings
Comprehensive cleanup of unused methods, dead code, and compiler warnings:

## Removed Methods (15):
- Duplicate delegation methods: is_authenticated, get_typing_text, get_user_name from TdClient
- Obsolete methods: TdClient::init() (duplicated in main.rs)
- Unused getters: UserCache::{get_username, get_name, get_user_id_by_chat}
- Unused builder methods: MessageBuilder::{edited, add_reaction}
- Unused utility: ChatState::is_normal()
- Dead code: HotkeysConfig::{matches, key_matches} (kept for tests)
- Unused method: UserCache::register_private_chat()
- Getter replaced with direct field access: MessageInfo::edit_date()

## Removed Module:
- error.rs - Unused error handling module (TeletuiError, ErrorVariant, IntoTeletuiError)

## Removed Constants (8):
- EMOJI_PICKER_COLUMNS, EMOJI_PICKER_ROWS, MAX_INPUT_HEIGHT
- MIN_TERMINAL_WIDTH, MIN_TERMINAL_HEIGHT
- TDLIB_CHAT_LIMIT, MAX_USERNAME_DISPLAY_LENGTH, MESSAGE_TEXT_INDENT

## Fixed Warnings:
- Removed unused imports (8 instances)
- Fixed unreachable patterns (10 instances)
- Fixed irrefutable if let patterns (2 instances)
- Fixed unused variables (1 instance)
- Removed dead_code annotations where appropriate

## Improvements:
- Integrated Config::load_credentials() into TdClient::new() for better credential management
- Replaced edit_date() getter with direct field access (message.metadata.edit_date)
- Updated tests to use direct field access instead of removed getters

## Test Results:
All tests passing: 499 passed, 0 failed

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 18:57:55 +03:00

419 lines
16 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.
// E2E User Journey tests — многошаговые интеграционные тесты
mod helpers;
use helpers::fake_tdclient::{FakeTdClient, TdUpdate};
use helpers::test_data::{TestChatBuilder, TestMessageBuilder};
use tele_tui::tdlib::NetworkState;
use tele_tui::types::{ChatId, MessageId};
/// Тест 1: App Launch → Auth → Chat List
/// Симулирует полный путь пользователя от запуска до загрузки чатов
#[tokio::test]
async fn test_user_journey_app_launch_to_chat_list() {
// 1. Создаем fake client (симуляция авторизации пропущена, клиент уже авторизован)
let client = FakeTdClient::new();
// 2. Проверяем начальное состояние - нет чатов
assert_eq!(client.get_chats().len(), 0);
assert_eq!(client.get_network_state(), NetworkState::Ready);
// 3. Создаем чаты
let chat1 = TestChatBuilder::new("Mom", 101).build();
let chat2 = TestChatBuilder::new("Work Group", 102).build();
let chat3 = TestChatBuilder::new("Boss", 103).build();
let client = client
.with_chat(chat1)
.with_chat(chat2)
.with_chat(chat3);
// 4. Симулируем загрузку чатов через load_chats
let loaded_chats = client.load_chats(50).await.unwrap();
// 5. Проверяем что чаты загружены
assert_eq!(loaded_chats.len(), 3);
assert_eq!(loaded_chats[0].title, "Mom");
assert_eq!(loaded_chats[1].title, "Work Group");
assert_eq!(loaded_chats[2].title, "Boss");
// 6. Проверяем что нет выбранного чата
assert_eq!(client.get_current_chat_id(), None);
}
/// Тест 2: Open Chat → Load History → Send Message
/// Симулирует открытие чата, загрузку истории и отправку сообщения
#[tokio::test]
async fn test_user_journey_open_chat_send_message() {
// 1. Подготовка: создаем клиент с чатом
let chat = TestChatBuilder::new("Mom", 123).build();
let client = FakeTdClient::new().with_chat(chat);
// 2. Создаем несколько сообщений в истории
let msg1 = TestMessageBuilder::new("Hi, how are you?", 1)
.sender("Mom")
.build();
let msg2 = TestMessageBuilder::new("I'm good, thanks!", 2)
.outgoing()
.build();
let client = client
.with_message(123, msg1)
.with_message(123, msg2);
// 3. Открываем чат
client.open_chat(ChatId::new(123)).await.unwrap();
// 4. Проверяем что чат открыт
assert_eq!(client.get_current_chat_id(), Some(123));
// 5. Загружаем историю сообщений
let history = client.get_chat_history(ChatId::new(123), 50).await.unwrap();
// 6. Проверяем что история загружена
assert_eq!(history.len(), 2);
assert_eq!(history[0].text(), "Hi, how are you?");
assert_eq!(history[1].text(), "I'm good, thanks!");
// 7. Отправляем новое сообщение
let _new_msg = client.send_message(
ChatId::new(123),
"What's for dinner?".to_string(),
None,
None
).await.unwrap();
// 8. Проверяем что сообщение отправлено
assert_eq!(client.get_sent_messages().len(), 1);
assert_eq!(client.get_sent_messages()[0].text, "What's for dinner?");
assert_eq!(client.get_sent_messages()[0].chat_id, 123);
// 9. Проверяем что сообщение добавилось в историю
let updated_history = client.get_chat_history(ChatId::new(123), 50).await.unwrap();
assert_eq!(updated_history.len(), 3);
assert_eq!(updated_history[2].text(), "What's for dinner?");
}
/// Тест 3: Receive Incoming Message While Chat Open
/// Симулирует получение входящего сообщения в открытом чате
#[tokio::test]
async fn test_user_journey_receive_incoming_message() {
// 1. Подготовка: создаем клиент с открытым чатом
let chat = TestChatBuilder::new("Friend", 456).build();
let client = FakeTdClient::new().with_chat(chat);
// 2. Открываем чат
client.open_chat(ChatId::new(456)).await.unwrap();
assert_eq!(client.get_current_chat_id(), Some(456));
// 3. Создаем update channel для получения событий
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
client.set_update_channel(tx);
// 4. Проверяем начальное состояние - нет сообщений
let initial_history = client.get_chat_history(ChatId::new(456), 50).await.unwrap();
assert_eq!(initial_history.len(), 0);
// 5. Симулируем входящее сообщение от собеседника
client.simulate_incoming_message(ChatId::new(456), "Hey! Are you there?".to_string(), "Friend");
// 6. Получаем update из канала
let update = rx.try_recv();
assert!(update.is_ok(), "Должен быть получен update о новом сообщении");
if let Ok(TdUpdate::NewMessage { chat_id, message }) = update {
assert_eq!(chat_id.as_i64(), 456);
assert_eq!(message.text(), "Hey! Are you there?");
assert_eq!(message.sender_name(), "Friend");
assert!(!message.is_outgoing());
} else {
panic!("Неверный тип update");
}
// 7. Проверяем что сообщение появилось в истории
let updated_history = client.get_chat_history(ChatId::new(456), 50).await.unwrap();
assert_eq!(updated_history.len(), 1);
assert_eq!(updated_history[0].text(), "Hey! Are you there?");
}
/// Тест 4: Multi-step conversation flow
/// Симулирует полноценную беседу с несколькими сообщениями туда-обратно
#[tokio::test]
async fn test_user_journey_multi_step_conversation() {
// 1. Подготовка
let chat = TestChatBuilder::new("Alice", 789).build();
let client = FakeTdClient::new().with_chat(chat);
// 2. Открываем чат
client.open_chat(ChatId::new(789)).await.unwrap();
// 3. Setup update channel
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
client.set_update_channel(tx);
// 4. Входящее сообщение от Alice
client.simulate_incoming_message(ChatId::new(789), "How's the project going?".to_string(), "Alice");
// Проверяем update
let update = rx.try_recv().ok();
assert!(matches!(update, Some(TdUpdate::NewMessage { .. })));
// 5. Отвечаем
client.send_message(
ChatId::new(789),
"Almost done! Just need to finish tests.".to_string(),
None,
None
).await.unwrap();
// 6. Проверяем историю после первого обмена
let history1 = client.get_chat_history(ChatId::new(789), 50).await.unwrap();
assert_eq!(history1.len(), 2);
// 7. Еще одно входящее сообщение
client.simulate_incoming_message(ChatId::new(789), "Great! Let me know if you need help.".to_string(), "Alice");
// 8. Снова отвечаем
client.send_message(
ChatId::new(789),
"Will do, thanks!".to_string(),
None,
None
).await.unwrap();
// 9. Финальная проверка истории
let final_history = client.get_chat_history(ChatId::new(789), 50).await.unwrap();
assert_eq!(final_history.len(), 4);
// Проверяем порядок сообщений
assert_eq!(final_history[0].text(), "How's the project going?");
assert!(!final_history[0].is_outgoing());
assert_eq!(final_history[1].text(), "Almost done! Just need to finish tests.");
assert!(final_history[1].is_outgoing());
assert_eq!(final_history[2].text(), "Great! Let me know if you need help.");
assert!(!final_history[2].is_outgoing());
assert_eq!(final_history[3].text(), "Will do, thanks!");
assert!(final_history[3].is_outgoing());
}
/// Тест 5: Switch between chats
/// Симулирует переключение между разными чатами
#[tokio::test]
async fn test_user_journey_switch_chats() {
// 1. Создаем несколько чатов
let chat1 = TestChatBuilder::new("Chat 1", 111).build();
let chat2 = TestChatBuilder::new("Chat 2", 222).build();
let chat3 = TestChatBuilder::new("Chat 3", 333).build();
let client = FakeTdClient::new()
.with_chat(chat1)
.with_chat(chat2)
.with_chat(chat3);
// 2. Открываем первый чат
client.open_chat(ChatId::new(111)).await.unwrap();
assert_eq!(client.get_current_chat_id(), Some(111));
// 3. Отправляем сообщение в первом чате
client.send_message(
ChatId::new(111),
"Message in chat 1".to_string(),
None,
None
).await.unwrap();
// 4. Переключаемся на второй чат
client.open_chat(ChatId::new(222)).await.unwrap();
assert_eq!(client.get_current_chat_id(), Some(222));
// 5. Отправляем сообщение во втором чате
client.send_message(
ChatId::new(222),
"Message in chat 2".to_string(),
None,
None
).await.unwrap();
// 6. Переключаемся на третий чат
client.open_chat(ChatId::new(333)).await.unwrap();
assert_eq!(client.get_current_chat_id(), Some(333));
// 7. Проверяем что сообщения были отправлены в правильные чаты
assert_eq!(client.get_sent_messages().len(), 2);
assert_eq!(client.get_sent_messages()[0].chat_id, 111);
assert_eq!(client.get_sent_messages()[0].text, "Message in chat 1");
assert_eq!(client.get_sent_messages()[1].chat_id, 222);
assert_eq!(client.get_sent_messages()[1].text, "Message in chat 2");
// 8. Проверяем истории отдельных чатов
let hist1 = client.get_chat_history(ChatId::new(111), 50).await.unwrap();
let hist2 = client.get_chat_history(ChatId::new(222), 50).await.unwrap();
let hist3 = client.get_chat_history(ChatId::new(333), 50).await.unwrap();
assert_eq!(hist1.len(), 1);
assert_eq!(hist2.len(), 1);
assert_eq!(hist3.len(), 0);
}
/// Тест 6: Edit message in conversation flow
/// Симулирует редактирование сообщения в процессе беседы
#[tokio::test]
async fn test_user_journey_edit_during_conversation() {
// 1. Подготовка
let chat = TestChatBuilder::new("Bob", 555).build();
let client = FakeTdClient::new().with_chat(chat);
client.open_chat(ChatId::new(555)).await.unwrap();
// 2. Отправляем сообщение с опечаткой
let msg = client.send_message(
ChatId::new(555),
"I'll be there at 5pm tomorow".to_string(),
None,
None
).await.unwrap();
// 3. Проверяем что сообщение отправлено
let history = client.get_chat_history(ChatId::new(555), 50).await.unwrap();
assert_eq!(history.len(), 1);
assert_eq!(history[0].text(), "I'll be there at 5pm tomorow");
// 4. Исправляем опечатку
client.edit_message(
ChatId::new(555),
msg.id(),
"I'll be there at 5pm tomorrow".to_string()
).await.unwrap();
// 5. Проверяем что сообщение отредактировано
let edited_history = client.get_chat_history(ChatId::new(555), 50).await.unwrap();
assert_eq!(edited_history.len(), 1);
assert_eq!(edited_history[0].text(), "I'll be there at 5pm tomorrow");
assert!(edited_history[0].metadata.edit_date > 0, "Должна быть установлена дата редактирования");
// 6. Проверяем историю редактирований
assert_eq!(client.get_edited_messages().len(), 1);
assert_eq!(client.get_edited_messages()[0].new_text, "I'll be there at 5pm tomorrow");
}
/// Тест 7: Reply to message in conversation
/// Симулирует ответ на конкретное сообщение
#[tokio::test]
async fn test_user_journey_reply_in_conversation() {
// 1. Подготовка
let chat = TestChatBuilder::new("Charlie", 666).build();
let client = FakeTdClient::new().with_chat(chat);
client.open_chat(ChatId::new(666)).await.unwrap();
// 2. Setup updates
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
client.set_update_channel(tx);
// 3. Входящее сообщение с вопросом
client.simulate_incoming_message(ChatId::new(666), "Can you send me the report?".to_string(), "Charlie");
let update = rx.try_recv().ok();
assert!(matches!(update, Some(TdUpdate::NewMessage { .. })));
let history = client.get_chat_history(ChatId::new(666), 50).await.unwrap();
let question_msg_id = history[0].id();
// 4. Отправляем другое сообщение (не связанное)
client.send_message(
ChatId::new(666),
"Working on it now".to_string(),
None,
None
).await.unwrap();
// 5. Отвечаем на конкретный вопрос (reply)
let reply_info = Some(tele_tui::tdlib::ReplyInfo {
message_id: question_msg_id,
sender_name: "Charlie".to_string(),
text: "Can you send me the report?".to_string(),
});
client.send_message(
ChatId::new(666),
"Sure, sending now!".to_string(),
Some(question_msg_id),
reply_info
).await.unwrap();
// 6. Проверяем что reply сохранён
let final_history = client.get_chat_history(ChatId::new(666), 50).await.unwrap();
assert_eq!(final_history.len(), 3);
// Последнее сообщение должно быть reply
let reply_msg = &final_history[2];
assert_eq!(reply_msg.text(), "Sure, sending now!");
assert!(reply_msg.interactions.reply_to.is_some());
let reply_to = reply_msg.interactions.reply_to.as_ref().unwrap();
assert_eq!(reply_to.message_id, question_msg_id);
assert_eq!(reply_to.text, "Can you send me the report?");
}
/// Тест 8: Network state changes during conversation
/// Симулирует изменения состояния сети во время работы
#[tokio::test]
async fn test_user_journey_network_state_changes() {
// 1. Подготовка
let chat = TestChatBuilder::new("Network Test", 888).build();
let client = FakeTdClient::new().with_chat(chat);
// 2. Setup updates
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
client.set_update_channel(tx);
// 3. Начальное состояние - Ready
assert_eq!(client.get_network_state(), NetworkState::Ready);
// 4. Открываем чат и отправляем сообщение
client.open_chat(ChatId::new(888)).await.unwrap();
client.send_message(
ChatId::new(888),
"Test message".to_string(),
None,
None
).await.unwrap();
// Очищаем канал от update NewMessage
let _ = rx.try_recv();
// 5. Симулируем потерю сети
client.simulate_network_change(NetworkState::WaitingForNetwork);
// Проверяем update
let update = rx.try_recv().ok();
assert!(matches!(update, Some(TdUpdate::ConnectionState { state: NetworkState::WaitingForNetwork })),
"Expected ConnectionState update, got: {:?}", update);
// 6. Проверяем что состояние изменилось
assert_eq!(client.get_network_state(), NetworkState::WaitingForNetwork);
// 7. Симулируем восстановление соединения
client.simulate_network_change(NetworkState::Connecting);
assert_eq!(client.get_network_state(), NetworkState::Connecting);
client.simulate_network_change(NetworkState::Ready);
assert_eq!(client.get_network_state(), NetworkState::Ready);
// 8. Отправляем сообщение после восстановления
client.send_message(
ChatId::new(888),
"Connection restored!".to_string(),
None,
None
).await.unwrap();
// 9. Проверяем что оба сообщения в истории
let history = client.get_chat_history(ChatId::new(888), 50).await.unwrap();
assert_eq!(history.len(), 2);
}