// 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); }