fixes
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
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
This commit is contained in:
151
tests/delete_message.rs
Normal file
151
tests/delete_message.rs
Normal file
@@ -0,0 +1,151 @@
|
||||
// Integration tests for delete message flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::TestMessageBuilder;
|
||||
|
||||
/// Test: Удаление сообщения убирает его из списка
|
||||
#[test]
|
||||
fn test_delete_message_removes_from_list() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем сообщение
|
||||
let msg_id = client.send_message(123, "Delete me".to_string(), None);
|
||||
|
||||
// Проверяем что сообщение есть
|
||||
assert_eq!(client.get_messages(123).len(), 1);
|
||||
|
||||
// Удаляем сообщение
|
||||
client.delete_message(123, msg_id);
|
||||
|
||||
// Проверяем что удаление записалось
|
||||
assert_eq!(client.deleted_messages().len(), 1);
|
||||
assert_eq!(client.deleted_messages()[0], msg_id);
|
||||
|
||||
// Проверяем что сообщение удалено из списка
|
||||
assert_eq!(client.get_messages(123).len(), 0);
|
||||
}
|
||||
|
||||
/// Test: Удаление нескольких сообщений
|
||||
#[test]
|
||||
fn test_delete_multiple_messages() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем 3 сообщения
|
||||
let msg1_id = client.send_message(123, "Message 1".to_string(), None);
|
||||
let msg2_id = client.send_message(123, "Message 2".to_string(), None);
|
||||
let msg3_id = client.send_message(123, "Message 3".to_string(), None);
|
||||
|
||||
assert_eq!(client.get_messages(123).len(), 3);
|
||||
|
||||
// Удаляем первое и третье
|
||||
client.delete_message(123, msg1_id);
|
||||
client.delete_message(123, msg3_id);
|
||||
|
||||
// Проверяем историю удалений
|
||||
assert_eq!(client.deleted_messages().len(), 2);
|
||||
assert_eq!(client.deleted_messages()[0], msg1_id);
|
||||
assert_eq!(client.deleted_messages()[1], msg3_id);
|
||||
|
||||
// Проверяем что осталось только второе сообщение
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].id, msg2_id);
|
||||
assert_eq!(messages[0].content, "Message 2");
|
||||
}
|
||||
|
||||
/// Test: Удаление только своих сообщений (проверка через can_be_deleted_for_all_users)
|
||||
#[test]
|
||||
fn test_can_only_delete_own_messages_for_all() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Наше исходящее сообщение (можно удалить для всех)
|
||||
let outgoing_msg = TestMessageBuilder::new("My message", 1)
|
||||
.outgoing()
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, outgoing_msg);
|
||||
|
||||
// Входящее сообщение от собеседника (можно удалить только для себя)
|
||||
let incoming_msg = TestMessageBuilder::new("Their message", 2)
|
||||
.sender("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, incoming_msg);
|
||||
|
||||
// Проверяем флаги удаления
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages[0].can_be_deleted_for_all_users, true); // Наше
|
||||
assert_eq!(messages[1].can_be_deleted_for_all_users, false); // Чужое
|
||||
|
||||
// Оба можно удалить для себя
|
||||
assert_eq!(messages[0].can_be_deleted_only_for_self, true);
|
||||
assert_eq!(messages[1].can_be_deleted_only_for_self, true);
|
||||
}
|
||||
|
||||
/// Test: Удаление несуществующего сообщения (ничего не происходит)
|
||||
#[test]
|
||||
fn test_delete_nonexistent_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем одно сообщение
|
||||
let msg_id = client.send_message(123, "Exists".to_string(), None);
|
||||
|
||||
assert_eq!(client.get_messages(123).len(), 1);
|
||||
|
||||
// Пытаемся удалить несуществующее
|
||||
client.delete_message(123, 999);
|
||||
|
||||
// Удаление записалось в историю
|
||||
assert_eq!(client.deleted_messages().len(), 1);
|
||||
assert_eq!(client.deleted_messages()[0], 999);
|
||||
|
||||
// Но существующее сообщение осталось
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].id, msg_id);
|
||||
}
|
||||
|
||||
/// Test: Подтверждение удаления (симуляция модалки)
|
||||
/// FakeTdClient сразу удаляет, но в реальном App должна быть модалка подтверждения
|
||||
#[test]
|
||||
fn test_delete_with_confirmation_flow() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg_id = client.send_message(123, "To delete".to_string(), None);
|
||||
|
||||
// Шаг 1: Пользователь нажал 'd' -> показывается модалка (в App)
|
||||
// В FakeTdClient просто проверяем что сообщение ещё есть
|
||||
assert_eq!(client.get_messages(123).len(), 1);
|
||||
assert_eq!(client.deleted_messages().len(), 0);
|
||||
|
||||
// Шаг 2: Пользователь подтвердил 'y' -> удаляем
|
||||
client.delete_message(123, msg_id);
|
||||
|
||||
// Проверяем что удалено
|
||||
assert_eq!(client.get_messages(123).len(), 0);
|
||||
assert_eq!(client.deleted_messages().len(), 1);
|
||||
}
|
||||
|
||||
/// Test: Отмена удаления (Esc) - сообщение остаётся
|
||||
#[test]
|
||||
fn test_cancel_delete_keeps_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg_id = client.send_message(123, "Keep me".to_string(), None);
|
||||
|
||||
// Шаг 1: Пользователь нажал 'd' -> показалась модалка
|
||||
assert_eq!(client.get_messages(123).len(), 1);
|
||||
|
||||
// Шаг 2: Пользователь нажал 'Esc' -> НЕ вызываем delete_message
|
||||
|
||||
// Проверяем что сообщение осталось
|
||||
assert_eq!(client.get_messages(123).len(), 1);
|
||||
assert_eq!(client.deleted_messages().len(), 0);
|
||||
|
||||
// Сообщение на месте
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages[0].id, msg_id);
|
||||
assert_eq!(messages[0].content, "Keep me");
|
||||
}
|
||||
192
tests/drafts.rs
Normal file
192
tests/drafts.rs
Normal file
@@ -0,0 +1,192 @@
|
||||
// Integration tests for drafts flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::test_data::{create_test_chat, TestChatBuilder};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Простая структура для хранения черновиков (как в реальном App)
|
||||
struct DraftManager {
|
||||
drafts: HashMap<i64, String>, // chat_id -> draft text
|
||||
}
|
||||
|
||||
impl DraftManager {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
drafts: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Сохранить черновик для чата
|
||||
fn save_draft(&mut self, chat_id: i64, text: String) {
|
||||
if text.is_empty() {
|
||||
self.drafts.remove(&chat_id);
|
||||
} else {
|
||||
self.drafts.insert(chat_id, text);
|
||||
}
|
||||
}
|
||||
|
||||
/// Получить черновик для чата
|
||||
fn get_draft(&self, chat_id: i64) -> Option<&String> {
|
||||
self.drafts.get(&chat_id)
|
||||
}
|
||||
|
||||
/// Очистить черновик для чата
|
||||
fn clear_draft(&mut self, chat_id: i64) {
|
||||
self.drafts.remove(&chat_id);
|
||||
}
|
||||
|
||||
/// Проверить есть ли черновик
|
||||
fn has_draft(&self, chat_id: i64) -> bool {
|
||||
self.drafts.contains_key(&chat_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Test: Переключение между чатами сохраняет текст
|
||||
#[test]
|
||||
fn test_switching_chats_saves_draft() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Пользователь в чате 123, начал печатать
|
||||
let current_chat = 123;
|
||||
let input_text = "Hello, this is a draft message";
|
||||
|
||||
// Перед переключением на другой чат - сохраняем
|
||||
drafts.save_draft(current_chat, input_text.to_string());
|
||||
|
||||
// Переключаемся на чат 456
|
||||
let _new_chat = 456;
|
||||
|
||||
// Проверяем что черновик для 123 сохранился
|
||||
assert!(drafts.has_draft(123));
|
||||
assert_eq!(drafts.get_draft(123).unwrap(), input_text);
|
||||
|
||||
// В новом чате 456 черновика нет
|
||||
assert!(!drafts.has_draft(456));
|
||||
}
|
||||
|
||||
/// Test: Возврат в чат восстанавливает текст
|
||||
#[test]
|
||||
fn test_returning_to_chat_restores_draft() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Сохраняем черновик в чате 123
|
||||
drafts.save_draft(123, "Unfinished message".to_string());
|
||||
|
||||
// Переключились на другие чаты
|
||||
// ...
|
||||
|
||||
// Возвращаемся в чат 123
|
||||
let restored_text = drafts.get_draft(123);
|
||||
|
||||
assert!(restored_text.is_some());
|
||||
assert_eq!(restored_text.unwrap(), "Unfinished message");
|
||||
}
|
||||
|
||||
/// Test: Отправка сообщения удаляет черновик
|
||||
#[test]
|
||||
fn test_sending_message_clears_draft() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Сохранили черновик
|
||||
drafts.save_draft(123, "Draft text".to_string());
|
||||
|
||||
assert!(drafts.has_draft(123));
|
||||
|
||||
// Пользователь отправил сообщение - очищаем черновик
|
||||
drafts.clear_draft(123);
|
||||
|
||||
assert!(!drafts.has_draft(123));
|
||||
assert_eq!(drafts.get_draft(123), None);
|
||||
}
|
||||
|
||||
/// Test: Индикатор черновика в списке чатов
|
||||
#[test]
|
||||
fn test_draft_indicator_in_chat_list() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Создаём несколько чатов
|
||||
let chat1 = create_test_chat("Mom", 123);
|
||||
let chat2 = TestChatBuilder::new("Boss", 456)
|
||||
.draft("Draft: Meeting notes")
|
||||
.build();
|
||||
let chat3 = create_test_chat("Friend", 789);
|
||||
|
||||
// В реальном App: chat.draft_text устанавливается из DraftManager
|
||||
// Здесь просто проверяем что у chat2 есть draft_text поле
|
||||
assert_eq!(chat2.draft_text.as_ref().unwrap(), "Draft: Meeting notes");
|
||||
|
||||
// Симулируем: пользователь набрал текст в чате 123
|
||||
drafts.save_draft(123, "My draft".to_string());
|
||||
|
||||
// Проверяем что драфт есть
|
||||
assert!(drafts.has_draft(123));
|
||||
assert_eq!(drafts.get_draft(123).unwrap(), "My draft");
|
||||
|
||||
// В UI рядом с чатом 123 будет показываться индикатор/превью
|
||||
// Например: "Mom" | "Draft: My draft"
|
||||
}
|
||||
|
||||
/// Test: Множественные черновики в разных чатах
|
||||
#[test]
|
||||
fn test_multiple_drafts_in_different_chats() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Создаём черновики в 3 чатах
|
||||
drafts.save_draft(123, "Draft for Mom".to_string());
|
||||
drafts.save_draft(456, "Draft for Boss".to_string());
|
||||
drafts.save_draft(789, "Draft for Friend".to_string());
|
||||
|
||||
// Проверяем что все сохранились
|
||||
assert_eq!(drafts.get_draft(123).unwrap(), "Draft for Mom");
|
||||
assert_eq!(drafts.get_draft(456).unwrap(), "Draft for Boss");
|
||||
assert_eq!(drafts.get_draft(789).unwrap(), "Draft for Friend");
|
||||
|
||||
// Очищаем один
|
||||
drafts.clear_draft(456);
|
||||
|
||||
// Проверяем что остальные на месте
|
||||
assert!(drafts.has_draft(123));
|
||||
assert!(!drafts.has_draft(456));
|
||||
assert!(drafts.has_draft(789));
|
||||
}
|
||||
|
||||
/// Test: Пустой текст не сохраняется как черновик
|
||||
#[test]
|
||||
fn test_empty_text_does_not_save_draft() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Пытаемся сохранить пустой черновик
|
||||
drafts.save_draft(123, "".to_string());
|
||||
|
||||
// Не должен сохраниться
|
||||
assert!(!drafts.has_draft(123));
|
||||
|
||||
// Сохраняем нормальный черновик
|
||||
drafts.save_draft(123, "Text".to_string());
|
||||
assert!(drafts.has_draft(123));
|
||||
|
||||
// Затем очищаем (сохраняем пустой)
|
||||
drafts.save_draft(123, "".to_string());
|
||||
|
||||
// Черновик должен удалиться
|
||||
assert!(!drafts.has_draft(123));
|
||||
}
|
||||
|
||||
/// Test: Редактирование черновика
|
||||
#[test]
|
||||
fn test_editing_draft() {
|
||||
let mut drafts = DraftManager::new();
|
||||
|
||||
// Сохраняем начальный черновик
|
||||
drafts.save_draft(123, "First version".to_string());
|
||||
assert_eq!(drafts.get_draft(123).unwrap(), "First version");
|
||||
|
||||
// Пользователь редактирует - сохраняем обновлённую версию
|
||||
drafts.save_draft(123, "Second version".to_string());
|
||||
assert_eq!(drafts.get_draft(123).unwrap(), "Second version");
|
||||
|
||||
// Ещё раз редактирует
|
||||
drafts.save_draft(123, "Final version".to_string());
|
||||
assert_eq!(drafts.get_draft(123).unwrap(), "Final version");
|
||||
}
|
||||
152
tests/edit_message.rs
Normal file
152
tests/edit_message.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
// Integration tests for edit message flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::TestMessageBuilder;
|
||||
|
||||
/// Test: Редактирование сообщения изменяет текст
|
||||
#[test]
|
||||
fn test_edit_message_changes_text() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем сообщение
|
||||
let msg_id = client.send_message(123, "Original text".to_string(), None);
|
||||
|
||||
// Редактируем сообщение
|
||||
client.edit_message(123, msg_id, "Edited text".to_string());
|
||||
|
||||
// Проверяем что редактирование записалось
|
||||
assert_eq!(client.edited_messages().len(), 1);
|
||||
assert_eq!(client.edited_messages()[0].message_id, msg_id);
|
||||
assert_eq!(client.edited_messages()[0].new_text, "Edited text");
|
||||
|
||||
// Проверяем что текст сообщения изменился
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].content, "Edited text");
|
||||
}
|
||||
|
||||
/// Test: Редактирование устанавливает edit_date
|
||||
#[test]
|
||||
fn test_edit_message_sets_edit_date() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем сообщение
|
||||
let msg_id = client.send_message(123, "Original".to_string(), None);
|
||||
|
||||
// Получаем дату до редактирования
|
||||
let messages_before = client.get_messages(123);
|
||||
let date_before = messages_before[0].date;
|
||||
assert_eq!(messages_before[0].edit_date, 0); // Не редактировалось
|
||||
|
||||
// Редактируем сообщение
|
||||
client.edit_message(123, msg_id, "Edited".to_string());
|
||||
|
||||
// Проверяем что edit_date установлена
|
||||
let messages_after = client.get_messages(123);
|
||||
assert!(messages_after[0].edit_date > 0);
|
||||
assert!(messages_after[0].edit_date > date_before); // edit_date после date
|
||||
}
|
||||
|
||||
/// Test: Редактирование только своих сообщений (проверка через can_be_edited)
|
||||
#[test]
|
||||
fn test_can_only_edit_own_messages() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Наше исходящее сообщение (можно редактировать)
|
||||
let outgoing_msg = TestMessageBuilder::new("My message", 1)
|
||||
.outgoing()
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, outgoing_msg);
|
||||
|
||||
// Входящее сообщение от собеседника (нельзя редактировать)
|
||||
let incoming_msg = TestMessageBuilder::new("Their message", 2)
|
||||
.sender("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, incoming_msg);
|
||||
|
||||
// Проверяем флаги
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages[0].can_be_edited, true); // Наше сообщение
|
||||
assert_eq!(messages[1].can_be_edited, false); // Чужое сообщение
|
||||
}
|
||||
|
||||
/// Test: Множественные редактирования одного сообщения
|
||||
#[test]
|
||||
fn test_multiple_edits_of_same_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg_id = client.send_message(123, "Version 1".to_string(), None);
|
||||
|
||||
// Первое редактирование
|
||||
client.edit_message(123, msg_id, "Version 2".to_string());
|
||||
|
||||
// Второе редактирование
|
||||
client.edit_message(123, msg_id, "Version 3".to_string());
|
||||
|
||||
// Третье редактирование
|
||||
client.edit_message(123, msg_id, "Final version".to_string());
|
||||
|
||||
// Проверяем что все 3 редактирования записаны
|
||||
assert_eq!(client.edited_messages().len(), 3);
|
||||
assert_eq!(client.edited_messages()[0].new_text, "Version 2");
|
||||
assert_eq!(client.edited_messages()[1].new_text, "Version 3");
|
||||
assert_eq!(client.edited_messages()[2].new_text, "Final version");
|
||||
|
||||
// Проверяем что сообщение содержит последнюю версию
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].content, "Final version");
|
||||
}
|
||||
|
||||
/// Test: Редактирование несуществующего сообщения (ничего не происходит)
|
||||
#[test]
|
||||
fn test_edit_nonexistent_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Пытаемся отредактировать несуществующее сообщение
|
||||
client.edit_message(123, 999, "New text".to_string());
|
||||
|
||||
// Редактирование записалось в историю (FakeTdClient всё записывает)
|
||||
assert_eq!(client.edited_messages().len(), 1);
|
||||
|
||||
// Но в списке сообщений ничего нет
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 0);
|
||||
}
|
||||
|
||||
/// Test: Отмена редактирования (Esc) - тестируем что можно восстановить original
|
||||
/// В данном случае проверяем что FakeTdClient сохраняет историю edits
|
||||
#[test]
|
||||
fn test_edit_history_tracking() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg_id = client.send_message(123, "Original".to_string(), None);
|
||||
|
||||
// Симулируем начало редактирования -> изменение -> отмена
|
||||
// Отменять на уровне FakeTdClient нельзя, но можно проверить что original сохранён
|
||||
|
||||
// Сохраняем original
|
||||
let messages_before = client.get_messages(123);
|
||||
let original = messages_before[0].content.clone();
|
||||
|
||||
// Редактируем
|
||||
client.edit_message(123, msg_id, "Edited".to_string());
|
||||
|
||||
// Проверяем что изменилось
|
||||
let messages_edited = client.get_messages(123);
|
||||
assert_eq!(messages_edited[0].content, "Edited");
|
||||
|
||||
// Можем "отменить" редактирование вернув original
|
||||
client.edit_message(123, msg_id, original);
|
||||
|
||||
// Проверяем что вернулось
|
||||
let messages_restored = client.get_messages(123);
|
||||
assert_eq!(messages_restored[0].content, "Original");
|
||||
|
||||
// История показывает 2 редактирования
|
||||
assert_eq!(client.edited_messages().len(), 2);
|
||||
}
|
||||
116
tests/footer.rs
Normal file
116
tests/footer.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
// Footer UI snapshot tests
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::test_data::create_test_chat;
|
||||
use helpers::app_builder::TestAppBuilder;
|
||||
use helpers::snapshot_utils::{render_to_buffer, buffer_to_string};
|
||||
use insta::assert_snapshot;
|
||||
use tele_tui::tdlib::NetworkState;
|
||||
|
||||
#[test]
|
||||
fn snapshot_footer_chat_list() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::footer::render(f, f.area(), &app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("footer_chat_list", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_footer_open_chat() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(123)
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::footer::render(f, f.area(), &app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("footer_open_chat", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_footer_network_waiting() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.build();
|
||||
|
||||
// Set network state to WaitingForNetwork
|
||||
app.td_client.network_state = NetworkState::WaitingForNetwork;
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::footer::render(f, f.area(), &app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("footer_network_waiting", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_footer_network_connecting_proxy() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.build();
|
||||
|
||||
// Set network state to ConnectingToProxy
|
||||
app.td_client.network_state = NetworkState::ConnectingToProxy;
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::footer::render(f, f.area(), &app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("footer_network_connecting_proxy", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_footer_network_connecting() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.build();
|
||||
|
||||
// Set network state to Connecting
|
||||
app.td_client.network_state = NetworkState::Connecting;
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::footer::render(f, f.area(), &app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("footer_network_connecting", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_footer_search_mode() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.searching("query")
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::footer::render(f, f.area(), &app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("footer_search_mode", output);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
use tele_tui::app::{App, AppScreen};
|
||||
use tele_tui::config::Config;
|
||||
use tele_tui::tdlib::{ChatInfo, MessageInfo};
|
||||
use tele_tui::tdlib::client::AuthState;
|
||||
use ratatui::widgets::ListState;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -31,6 +32,11 @@ pub struct TestAppBuilder {
|
||||
message_search_query: String,
|
||||
forwarding_message_id: Option<i64>,
|
||||
is_selecting_forward_chat: bool,
|
||||
status_message: Option<String>,
|
||||
auth_state: Option<AuthState>,
|
||||
phone_input: Option<String>,
|
||||
code_input: Option<String>,
|
||||
password_input: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for TestAppBuilder {
|
||||
@@ -60,6 +66,11 @@ impl TestAppBuilder {
|
||||
message_search_query: String::new(),
|
||||
forwarding_message_id: None,
|
||||
is_selecting_forward_chat: false,
|
||||
status_message: None,
|
||||
auth_state: None,
|
||||
phone_input: None,
|
||||
code_input: None,
|
||||
password_input: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +179,36 @@ impl TestAppBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Установить статус сообщение (для loading screen)
|
||||
pub fn status_message(mut self, message: &str) -> Self {
|
||||
self.status_message = Some(message.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Установить auth state
|
||||
pub fn auth_state(mut self, state: AuthState) -> Self {
|
||||
self.auth_state = Some(state);
|
||||
self
|
||||
}
|
||||
|
||||
/// Установить phone input
|
||||
pub fn phone_input(mut self, phone: &str) -> Self {
|
||||
self.phone_input = Some(phone.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Установить code input
|
||||
pub fn code_input(mut self, code: &str) -> Self {
|
||||
self.code_input = Some(code.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Установить password input
|
||||
pub fn password_input(mut self, password: &str) -> Self {
|
||||
self.password_input = Some(password.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Построить App
|
||||
///
|
||||
/// ВАЖНО: Этот метод создаёт App с реальным TdClient,
|
||||
@@ -193,6 +234,27 @@ impl TestAppBuilder {
|
||||
app.forwarding_message_id = self.forwarding_message_id;
|
||||
app.is_selecting_forward_chat = self.is_selecting_forward_chat;
|
||||
|
||||
// Применяем status_message
|
||||
if let Some(status) = self.status_message {
|
||||
app.status_message = Some(status);
|
||||
}
|
||||
|
||||
// Применяем auth state
|
||||
if let Some(auth_state) = self.auth_state {
|
||||
app.td_client.auth_state = auth_state;
|
||||
}
|
||||
|
||||
// Применяем auth inputs
|
||||
if let Some(phone) = self.phone_input {
|
||||
app.phone_input = phone;
|
||||
}
|
||||
if let Some(code) = self.code_input {
|
||||
app.code_input = code;
|
||||
}
|
||||
if let Some(password) = self.password_input {
|
||||
app.password_input = password;
|
||||
}
|
||||
|
||||
// Выбираем первый чат если есть
|
||||
if !app.chats.is_empty() {
|
||||
let mut list_state = ListState::default();
|
||||
|
||||
149
tests/input_field.rs
Normal file
149
tests/input_field.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
// Input Field UI snapshot tests
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::test_data::{TestMessageBuilder, create_test_chat};
|
||||
use helpers::app_builder::TestAppBuilder;
|
||||
use helpers::snapshot_utils::{render_to_buffer, buffer_to_string};
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn snapshot_empty_input() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(123)
|
||||
.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!("empty_input", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_input_with_text() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(123)
|
||||
.message_input("Hello, how are you?")
|
||||
.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!("input_with_text", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_input_long_text_2_lines() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
// Text that wraps to 2 lines
|
||||
let long_text = "This is a longer message that will wrap to multiple lines in the input field for testing purposes.";
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(123)
|
||||
.message_input(long_text)
|
||||
.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!("input_long_text_2_lines", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_input_long_text_max_lines() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
// Very long text that reaches maximum 10 lines
|
||||
let very_long_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.";
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(123)
|
||||
.message_input(very_long_text)
|
||||
.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!("input_long_text_max_lines", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_input_editing_mode() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
let message = TestMessageBuilder::new("Original message text", 1)
|
||||
.outgoing()
|
||||
.build();
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.with_message(123, message)
|
||||
.selected_chat(123)
|
||||
.editing_message(1)
|
||||
.message_input("Edited text here")
|
||||
.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!("input_editing_mode", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_input_reply_mode() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
let original_msg = TestMessageBuilder::new("What do you think about this?", 1)
|
||||
.sender("Mom")
|
||||
.build();
|
||||
|
||||
let app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.with_message(123, original_msg)
|
||||
.selected_chat(123)
|
||||
.replying_to(1)
|
||||
.message_input("I think it's great!")
|
||||
.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!("input_reply_mode", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_input_search_mode() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.with_chat(chat)
|
||||
.selected_chat(123)
|
||||
.searching("hello")
|
||||
.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!("input_search_mode", output);
|
||||
}
|
||||
230
tests/navigation.rs
Normal file
230
tests/navigation.rs
Normal file
@@ -0,0 +1,230 @@
|
||||
// Integration tests for navigation flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::{create_test_chat, TestMessageBuilder};
|
||||
|
||||
/// Test: Навигация вверх/вниз по списку чатов
|
||||
#[test]
|
||||
fn test_navigate_chat_list_up_down() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat1 = create_test_chat("Mom", 123);
|
||||
let chat2 = create_test_chat("Boss", 456);
|
||||
let chat3 = create_test_chat("Friend", 789);
|
||||
|
||||
client = client.with_chats(vec![chat1, chat2, chat3]);
|
||||
|
||||
let chats = client.get_chats();
|
||||
|
||||
// Начинаем с индекса 0
|
||||
let mut selected_index = 0;
|
||||
assert_eq!(chats[selected_index].title, "Mom");
|
||||
|
||||
// ↓ - вниз
|
||||
selected_index = (selected_index + 1).min(chats.len() - 1);
|
||||
assert_eq!(selected_index, 1);
|
||||
assert_eq!(chats[selected_index].title, "Boss");
|
||||
|
||||
// ↓ - ещё вниз
|
||||
selected_index = (selected_index + 1).min(chats.len() - 1);
|
||||
assert_eq!(selected_index, 2);
|
||||
assert_eq!(chats[selected_index].title, "Friend");
|
||||
|
||||
// ↓ - на границе (не должно выйти за пределы)
|
||||
selected_index = (selected_index + 1).min(chats.len() - 1);
|
||||
assert_eq!(selected_index, 2); // Остался на последнем
|
||||
|
||||
// ↑ - вверх
|
||||
selected_index = selected_index.saturating_sub(1);
|
||||
assert_eq!(selected_index, 1);
|
||||
assert_eq!(chats[selected_index].title, "Boss");
|
||||
|
||||
// ↑ - ещё вверх
|
||||
selected_index = selected_index.saturating_sub(1);
|
||||
assert_eq!(selected_index, 0);
|
||||
assert_eq!(chats[selected_index].title, "Mom");
|
||||
|
||||
// ↑ - на границе (не должно выйти за пределы)
|
||||
selected_index = selected_index.saturating_sub(1);
|
||||
assert_eq!(selected_index, 0); // Остался на первом
|
||||
}
|
||||
|
||||
/// Test: Enter открывает чат
|
||||
#[test]
|
||||
fn test_enter_opens_chat() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
let _client = client.with_chat(chat);
|
||||
|
||||
// Состояние: список чатов, выбран чат 123
|
||||
let selected_chat_id: Option<i64> = None;
|
||||
|
||||
// Пользователь нажал Enter
|
||||
let new_selected_chat_id = Some(123);
|
||||
|
||||
assert_eq!(selected_chat_id, None);
|
||||
assert_eq!(new_selected_chat_id, Some(123));
|
||||
}
|
||||
|
||||
/// Test: Esc закрывает чат
|
||||
#[test]
|
||||
fn test_esc_closes_chat() {
|
||||
// Состояние: открыт чат 123
|
||||
let selected_chat_id = Some(123);
|
||||
|
||||
// Пользователь нажал Esc
|
||||
let selected_chat_id: Option<i64> = None;
|
||||
|
||||
assert_eq!(selected_chat_id, None);
|
||||
}
|
||||
|
||||
/// Test: Скролл сообщений в чате
|
||||
#[test]
|
||||
fn test_scroll_messages_in_chat() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let messages = vec![
|
||||
TestMessageBuilder::new("Msg 1", 1).build(),
|
||||
TestMessageBuilder::new("Msg 2", 2).build(),
|
||||
TestMessageBuilder::new("Msg 3", 3).build(),
|
||||
TestMessageBuilder::new("Msg 4", 4).build(),
|
||||
TestMessageBuilder::new("Msg 5", 5).build(),
|
||||
];
|
||||
|
||||
client = client.with_messages(123, messages);
|
||||
|
||||
let msgs = client.get_messages(123);
|
||||
|
||||
// Скролл начинается снизу (последнее сообщение видно)
|
||||
let mut scroll_offset: usize = 0;
|
||||
|
||||
// ↑ - скролл вверх (увеличиваем offset)
|
||||
scroll_offset += 1;
|
||||
assert_eq!(scroll_offset, 1);
|
||||
|
||||
// ↑ - ещё вверх
|
||||
scroll_offset += 1;
|
||||
assert_eq!(scroll_offset, 2);
|
||||
|
||||
// ↓ - скролл вниз (уменьшаем offset)
|
||||
scroll_offset = scroll_offset.saturating_sub(1);
|
||||
assert_eq!(scroll_offset, 1);
|
||||
|
||||
// ↓ - к низу
|
||||
scroll_offset = scroll_offset.saturating_sub(1);
|
||||
assert_eq!(scroll_offset, 0);
|
||||
|
||||
// ↓ - на границе
|
||||
scroll_offset = scroll_offset.saturating_sub(1);
|
||||
assert_eq!(scroll_offset, 0); // Не уходим в минус
|
||||
}
|
||||
|
||||
/// Test: Переключение между папками (1-9)
|
||||
#[test]
|
||||
fn test_switch_folders() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Добавляем папки (FakeTdClient уже создаёт "All" с id=0)
|
||||
client = client
|
||||
.with_folder(1, "Personal")
|
||||
.with_folder(2, "Work");
|
||||
|
||||
let folders = client.get_folders();
|
||||
|
||||
// Проверяем что папки на месте
|
||||
assert_eq!(folders.len(), 3);
|
||||
assert_eq!(folders[0].name, "All");
|
||||
assert_eq!(folders[1].name, "Personal");
|
||||
assert_eq!(folders[2].name, "Work");
|
||||
|
||||
// Начинаем с папки 0 (All)
|
||||
let mut selected_folder_index = 0;
|
||||
assert_eq!(folders[selected_folder_index].name, "All");
|
||||
|
||||
// Нажали '1' - папка Personal (индекс 1)
|
||||
selected_folder_index = 1;
|
||||
assert_eq!(folders[selected_folder_index].name, "Personal");
|
||||
|
||||
// Нажали '2' - папка Work (индекс 2)
|
||||
selected_folder_index = 2;
|
||||
assert_eq!(folders[selected_folder_index].name, "Work");
|
||||
|
||||
// Нажали '0' (или Esc из папки) - обратно в All (индекс 0)
|
||||
selected_folder_index = 0;
|
||||
assert_eq!(folders[selected_folder_index].name, "All");
|
||||
}
|
||||
|
||||
/// Test: Русская раскладка для навигации (р/о/л/д)
|
||||
#[test]
|
||||
fn test_russian_layout_navigation() {
|
||||
// В реальном App: к/j/h/l маппятся на р/о/л/д для русской раскладки
|
||||
|
||||
// Mapping:
|
||||
// j (down) <-> о
|
||||
// k (up) <-> л
|
||||
// h (left) <-> р
|
||||
// l (right) <-> д
|
||||
|
||||
let mut selected_index = 1;
|
||||
|
||||
// Симулируем нажатие 'о' (как 'j' - вниз)
|
||||
selected_index += 1;
|
||||
assert_eq!(selected_index, 2);
|
||||
|
||||
// 'л' (как 'k' - вверх)
|
||||
selected_index -= 1;
|
||||
assert_eq!(selected_index, 1);
|
||||
|
||||
// Проверяем что логика работает одинаково
|
||||
assert!(true); // Реальный тест был бы в input handler
|
||||
}
|
||||
|
||||
/// Test: Подгрузка старых сообщений при скролле вверх
|
||||
#[test]
|
||||
fn test_load_older_messages_on_scroll_up() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Начальные сообщения (последние 10)
|
||||
let initial_messages = vec![
|
||||
TestMessageBuilder::new("Msg 91", 91).build(),
|
||||
TestMessageBuilder::new("Msg 92", 92).build(),
|
||||
TestMessageBuilder::new("Msg 93", 93).build(),
|
||||
TestMessageBuilder::new("Msg 94", 94).build(),
|
||||
TestMessageBuilder::new("Msg 95", 95).build(),
|
||||
TestMessageBuilder::new("Msg 96", 96).build(),
|
||||
TestMessageBuilder::new("Msg 97", 97).build(),
|
||||
TestMessageBuilder::new("Msg 98", 98).build(),
|
||||
TestMessageBuilder::new("Msg 99", 99).build(),
|
||||
TestMessageBuilder::new("Msg 100", 100).build(),
|
||||
];
|
||||
|
||||
client = client.with_messages(123, initial_messages);
|
||||
|
||||
assert_eq!(client.get_messages(123).len(), 10);
|
||||
|
||||
// Пользователь скроллит до самого верха (дошёл до Msg 91)
|
||||
// Триггерим подгрузку старых сообщений
|
||||
|
||||
// Симулируем подгрузку (добавляем старые сообщения в начало)
|
||||
let older_messages = vec![
|
||||
TestMessageBuilder::new("Msg 81", 81).build(),
|
||||
TestMessageBuilder::new("Msg 82", 82).build(),
|
||||
TestMessageBuilder::new("Msg 83", 83).build(),
|
||||
TestMessageBuilder::new("Msg 84", 84).build(),
|
||||
TestMessageBuilder::new("Msg 85", 85).build(),
|
||||
];
|
||||
|
||||
// Добавляем к существующим (в реальности - prepend)
|
||||
let mut all_messages = older_messages;
|
||||
all_messages.extend(client.get_messages(123));
|
||||
|
||||
client.messages.insert(123, all_messages);
|
||||
|
||||
// Теперь должно быть 15 сообщений
|
||||
assert_eq!(client.get_messages(123).len(), 15);
|
||||
assert_eq!(client.get_messages(123)[0].content, "Msg 81");
|
||||
assert_eq!(client.get_messages(123)[14].content, "Msg 100");
|
||||
}
|
||||
168
tests/network_typing.rs
Normal file
168
tests/network_typing.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
// Integration tests for network and typing flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::create_test_chat;
|
||||
use tele_tui::tdlib::NetworkState;
|
||||
|
||||
/// Test: Смена состояния сети отображается в UI
|
||||
#[test]
|
||||
fn test_network_state_changes() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Начальное состояние - Ready
|
||||
assert_eq!(client.network_state, NetworkState::Ready);
|
||||
|
||||
// Сеть пропала
|
||||
client.network_state = NetworkState::WaitingForNetwork;
|
||||
assert_eq!(client.network_state, NetworkState::WaitingForNetwork);
|
||||
// В UI: "⚠ Нет сети"
|
||||
|
||||
// Подключаемся к прокси
|
||||
client.network_state = NetworkState::ConnectingToProxy;
|
||||
assert_eq!(client.network_state, NetworkState::ConnectingToProxy);
|
||||
// В UI: "⏳ Прокси..."
|
||||
|
||||
// Подключаемся к серверам
|
||||
client.network_state = NetworkState::Connecting;
|
||||
assert_eq!(client.network_state, NetworkState::Connecting);
|
||||
// В UI: "⏳ Подключение..."
|
||||
|
||||
// Соединение восстановлено
|
||||
client.network_state = NetworkState::Ready;
|
||||
assert_eq!(client.network_state, NetworkState::Ready);
|
||||
// В UI: индикатор скрывается
|
||||
}
|
||||
|
||||
/// Test: WaitingForNetwork - нет подключения
|
||||
#[test]
|
||||
fn test_network_waiting_for_network() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
client.network_state = NetworkState::WaitingForNetwork;
|
||||
|
||||
assert_eq!(client.network_state, NetworkState::WaitingForNetwork);
|
||||
|
||||
// В этом состоянии:
|
||||
// - Показывается предупреждение "⚠ Нет сети"
|
||||
// - Отправка сообщений заблокирована
|
||||
// - Updates не приходят
|
||||
}
|
||||
|
||||
/// Test: ConnectingToProxy - подключение через прокси
|
||||
#[test]
|
||||
fn test_network_connecting_to_proxy() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
client.network_state = NetworkState::ConnectingToProxy;
|
||||
|
||||
assert_eq!(client.network_state, NetworkState::ConnectingToProxy);
|
||||
|
||||
// В UI: "⏳ Прокси..."
|
||||
}
|
||||
|
||||
/// Test: Connecting - подключение к серверам Telegram
|
||||
#[test]
|
||||
fn test_network_connecting() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
client.network_state = NetworkState::Connecting;
|
||||
|
||||
assert_eq!(client.network_state, NetworkState::Connecting);
|
||||
|
||||
// В UI: "⏳ Подключение..."
|
||||
}
|
||||
|
||||
/// Test: Updating - обновление данных
|
||||
#[test]
|
||||
fn test_network_updating() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
client.network_state = NetworkState::Updating;
|
||||
|
||||
assert_eq!(client.network_state, NetworkState::Updating);
|
||||
|
||||
// В UI: "⏳ Обновление..."
|
||||
}
|
||||
|
||||
/// Test: Typing indicator - пользователь печатает
|
||||
#[test]
|
||||
fn test_typing_indicator_on() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat = create_test_chat("Alice", 123);
|
||||
client = client.with_chat(chat);
|
||||
|
||||
// Alice начала печатать в чате 123
|
||||
client.set_typing(Some(123));
|
||||
|
||||
assert_eq!(client.typing_chat_id, Some(123));
|
||||
|
||||
// В UI: под сообщениями отображается "Alice печатает..."
|
||||
}
|
||||
|
||||
/// Test: Typing indicator - пользователь перестал печатать
|
||||
#[test]
|
||||
fn test_typing_indicator_off() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Изначально Alice печатала
|
||||
client.set_typing(Some(123));
|
||||
assert_eq!(client.typing_chat_id, Some(123));
|
||||
|
||||
// Alice перестала печатать
|
||||
client.set_typing(None);
|
||||
|
||||
assert_eq!(client.typing_chat_id, None);
|
||||
|
||||
// В UI: индикатор "печатает..." исчезает
|
||||
}
|
||||
|
||||
/// Test: Отправка своего typing status
|
||||
#[test]
|
||||
fn test_send_own_typing_status() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Пользователь начал печатать в чате 456
|
||||
// В реальном App вызывается client.send_chat_action(chat_id, ChatAction::Typing)
|
||||
|
||||
// Симулируем: устанавливаем что мы печатаем
|
||||
let our_typing_chat_id = Some(456);
|
||||
|
||||
assert_eq!(our_typing_chat_id, Some(456));
|
||||
|
||||
// Собеседник видит что мы печатаем
|
||||
|
||||
// Через некоторое время (или при отправке сообщения) - отменяем
|
||||
// client.send_chat_action(chat_id, ChatAction::Cancel)
|
||||
let our_typing_chat_id: Option<i64> = None;
|
||||
|
||||
assert_eq!(our_typing_chat_id, None);
|
||||
}
|
||||
|
||||
/// Test: Множественные переходы состояний сети
|
||||
#[test]
|
||||
fn test_multiple_network_state_transitions() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Цикл переходов состояний
|
||||
let states = vec![
|
||||
NetworkState::Ready,
|
||||
NetworkState::Connecting,
|
||||
NetworkState::Ready,
|
||||
NetworkState::WaitingForNetwork,
|
||||
NetworkState::ConnectingToProxy,
|
||||
NetworkState::Connecting,
|
||||
NetworkState::Updating,
|
||||
NetworkState::Ready,
|
||||
];
|
||||
|
||||
for state in states {
|
||||
client.network_state = state.clone();
|
||||
assert_eq!(client.network_state, state);
|
||||
}
|
||||
|
||||
// Финальное состояние - Ready
|
||||
assert_eq!(client.network_state, NetworkState::Ready);
|
||||
}
|
||||
133
tests/profile.rs
Normal file
133
tests/profile.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
// Integration tests for profile flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::create_test_chat;
|
||||
use tele_tui::tdlib::ProfileInfo;
|
||||
|
||||
/// Test: Открытие профиля в личном чате (i)
|
||||
#[test]
|
||||
fn test_open_profile_in_private_chat() {
|
||||
let client = FakeTdClient::new();
|
||||
|
||||
let chat = create_test_chat("Alice", 123);
|
||||
let _client = client.with_chat(chat);
|
||||
|
||||
// Пользователь открыл чат и нажал 'i'
|
||||
let profile_mode = true;
|
||||
|
||||
assert!(profile_mode);
|
||||
|
||||
// В реальном App загрузится ProfileInfo для этого чата
|
||||
}
|
||||
|
||||
/// Test: Профиль показывает имя, username, телефон
|
||||
#[test]
|
||||
fn test_profile_shows_user_info() {
|
||||
let profile = ProfileInfo {
|
||||
chat_id: 123,
|
||||
title: "Alice Johnson".to_string(),
|
||||
username: Some("alice".to_string()),
|
||||
phone_number: Some("+1234567890".to_string()),
|
||||
bio: None,
|
||||
chat_type: "Личный чат".to_string(),
|
||||
member_count: None,
|
||||
description: None,
|
||||
invite_link: None,
|
||||
is_group: false,
|
||||
online_status: Some("Online".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(profile.title, "Alice Johnson");
|
||||
assert_eq!(profile.username.as_ref().unwrap(), "alice");
|
||||
assert_eq!(profile.phone_number.as_ref().unwrap(), "+1234567890");
|
||||
assert_eq!(profile.chat_type, "Личный чат");
|
||||
}
|
||||
|
||||
/// Test: Профиль в группе показывает количество участников
|
||||
#[test]
|
||||
fn test_profile_shows_group_member_count() {
|
||||
let profile = ProfileInfo {
|
||||
chat_id: 456,
|
||||
title: "Work Team".to_string(),
|
||||
username: None,
|
||||
phone_number: None,
|
||||
bio: Some("Our work group".to_string()),
|
||||
chat_type: "Группа".to_string(),
|
||||
member_count: Some(25),
|
||||
description: None,
|
||||
invite_link: None,
|
||||
is_group: true,
|
||||
online_status: None,
|
||||
};
|
||||
|
||||
assert_eq!(profile.title, "Work Team");
|
||||
assert_eq!(profile.chat_type, "Группа");
|
||||
assert_eq!(profile.member_count, Some(25));
|
||||
assert_eq!(profile.bio.as_ref().unwrap(), "Our work group");
|
||||
}
|
||||
|
||||
/// Test: Профиль в канале
|
||||
#[test]
|
||||
fn test_profile_shows_channel_info() {
|
||||
let profile = ProfileInfo {
|
||||
chat_id: 789,
|
||||
title: "News Channel".to_string(),
|
||||
username: Some("news_channel".to_string()),
|
||||
phone_number: None,
|
||||
bio: Some("Latest news updates".to_string()),
|
||||
chat_type: "Канал".to_string(),
|
||||
member_count: Some(1000),
|
||||
description: Some("Latest news updates".to_string()),
|
||||
invite_link: Some("t.me/news_channel".to_string()),
|
||||
is_group: false,
|
||||
online_status: None,
|
||||
};
|
||||
|
||||
assert_eq!(profile.title, "News Channel");
|
||||
assert_eq!(profile.username.as_ref().unwrap(), "news_channel");
|
||||
assert_eq!(profile.chat_type, "Канал");
|
||||
assert_eq!(profile.member_count, Some(1000)); // Subscribers
|
||||
}
|
||||
|
||||
/// Test: Закрытие профиля (Esc)
|
||||
#[test]
|
||||
fn test_close_profile_with_esc() {
|
||||
// Профиль открыт
|
||||
let profile_mode = true;
|
||||
|
||||
// Пользователь нажал Esc
|
||||
let profile_mode = false;
|
||||
|
||||
assert!(!profile_mode);
|
||||
}
|
||||
|
||||
/// Test: Профиль без username и phone
|
||||
#[test]
|
||||
fn test_profile_without_optional_fields() {
|
||||
let profile = ProfileInfo {
|
||||
chat_id: 999,
|
||||
title: "Anonymous User".to_string(),
|
||||
username: None,
|
||||
phone_number: None,
|
||||
bio: None,
|
||||
chat_type: "Личный чат".to_string(),
|
||||
member_count: None,
|
||||
description: None,
|
||||
invite_link: None,
|
||||
is_group: false,
|
||||
online_status: None,
|
||||
};
|
||||
|
||||
// Обязательные поля заполнены
|
||||
assert_eq!(profile.title, "Anonymous User");
|
||||
assert_eq!(profile.chat_type, "Личный чат");
|
||||
|
||||
// Опциональные поля None
|
||||
assert_eq!(profile.username, None);
|
||||
assert_eq!(profile.phone_number, None);
|
||||
assert_eq!(profile.bio, None);
|
||||
|
||||
// В UI будут отображаться только доступные поля
|
||||
}
|
||||
243
tests/reactions.rs
Normal file
243
tests/reactions.rs
Normal file
@@ -0,0 +1,243 @@
|
||||
// Integration tests for reactions flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::TestMessageBuilder;
|
||||
|
||||
/// Test: Добавление реакции к сообщению
|
||||
#[test]
|
||||
fn test_add_reaction_to_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем сообщение
|
||||
let msg_id = client.send_message(123, "React to this!".to_string(), None);
|
||||
|
||||
// Добавляем реакцию
|
||||
client.add_reaction(msg_id, "👍".to_string());
|
||||
|
||||
// Проверяем что реакция записалась
|
||||
let reactions = client.reactions.get(&msg_id);
|
||||
assert!(reactions.is_some());
|
||||
assert_eq!(reactions.unwrap().len(), 1);
|
||||
assert_eq!(reactions.unwrap()[0], "👍");
|
||||
}
|
||||
|
||||
/// Test: Удаление реакции (toggle) - вторичное нажатие
|
||||
#[test]
|
||||
fn test_toggle_reaction_removes_it() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём сообщение с нашей реакцией
|
||||
let msg = TestMessageBuilder::new("Message", 100)
|
||||
.reaction("👍", 1, true) // chosen=true - наша реакция
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg);
|
||||
|
||||
// Проверяем что реакция есть
|
||||
let messages_before = client.get_messages(123);
|
||||
assert_eq!(messages_before[0].reactions.len(), 1);
|
||||
assert_eq!(messages_before[0].reactions[0].is_chosen, true);
|
||||
|
||||
// Симулируем удаление реакции (в реальном App это toggle)
|
||||
// FakeTdClient просто записывает что реакция была "убрана"
|
||||
// Для теста можем удалить из списка вручную или расширить FakeTdClient
|
||||
|
||||
// Создаём сообщение без реакции (после toggle)
|
||||
let msg_after = TestMessageBuilder::new("Message", 100).build();
|
||||
|
||||
// Заменяем в клиенте
|
||||
client.messages.insert(123, vec![msg_after]);
|
||||
|
||||
let messages_after = client.get_messages(123);
|
||||
assert_eq!(messages_after[0].reactions.len(), 0);
|
||||
}
|
||||
|
||||
/// Test: Множественные реакции на одно сообщение
|
||||
#[test]
|
||||
fn test_multiple_reactions_on_one_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg_id = client.send_message(123, "Many reactions".to_string(), None);
|
||||
|
||||
// Добавляем несколько разных реакций
|
||||
client.add_reaction(msg_id, "👍".to_string());
|
||||
client.add_reaction(msg_id, "❤️".to_string());
|
||||
client.add_reaction(msg_id, "😂".to_string());
|
||||
client.add_reaction(msg_id, "🔥".to_string());
|
||||
|
||||
// Проверяем что все 4 реакции записались
|
||||
let reactions = client.reactions.get(&msg_id).unwrap();
|
||||
assert_eq!(reactions.len(), 4);
|
||||
assert_eq!(reactions[0], "👍");
|
||||
assert_eq!(reactions[1], "❤️");
|
||||
assert_eq!(reactions[2], "😂");
|
||||
assert_eq!(reactions[3], "🔥");
|
||||
}
|
||||
|
||||
/// Test: Реакции от разных пользователей (count > 1)
|
||||
#[test]
|
||||
fn test_reactions_from_multiple_users() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём сообщение с реакцией от 3 пользователей
|
||||
let msg = TestMessageBuilder::new("Popular message", 100)
|
||||
.reaction("👍", 3, false) // 3 человека, но не мы
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
let reaction = &messages[0].reactions[0];
|
||||
|
||||
assert_eq!(reaction.emoji, "👍");
|
||||
assert_eq!(reaction.count, 3);
|
||||
assert_eq!(reaction.is_chosen, false);
|
||||
}
|
||||
|
||||
/// Test: Своя реакция (is_chosen = true)
|
||||
#[test]
|
||||
fn test_own_reaction_is_chosen() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём сообщение с нашей реакцией
|
||||
let msg = TestMessageBuilder::new("I reacted", 100)
|
||||
.reaction("❤️", 1, true) // chosen=true
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
let reaction = &messages[0].reactions[0];
|
||||
|
||||
assert_eq!(reaction.is_chosen, true);
|
||||
// В UI это будет отображаться в рамках: [❤️]
|
||||
}
|
||||
|
||||
/// Test: Чужая реакция (is_chosen = false)
|
||||
#[test]
|
||||
fn test_other_reaction_not_chosen() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём сообщение с чужой реакцией
|
||||
let msg = TestMessageBuilder::new("They reacted", 100)
|
||||
.reaction("😂", 2, false) // chosen=false
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
let reaction = &messages[0].reactions[0];
|
||||
|
||||
assert_eq!(reaction.is_chosen, false);
|
||||
// В UI это будет отображаться без рамок: 😂 2
|
||||
}
|
||||
|
||||
/// Test: Счётчик реакций увеличивается
|
||||
#[test]
|
||||
fn test_reaction_counter_increases() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Начальное сообщение с 1 реакцией
|
||||
let msg_v1 = TestMessageBuilder::new("Growing", 100)
|
||||
.reaction("👍", 1, false)
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg_v1);
|
||||
|
||||
// Симулируем обновление: теперь 5 человек
|
||||
let msg_v2 = TestMessageBuilder::new("Growing", 100)
|
||||
.reaction("👍", 5, false)
|
||||
.build();
|
||||
|
||||
client.messages.insert(123, vec![msg_v2]);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages[0].reactions[0].count, 5);
|
||||
}
|
||||
|
||||
/// Test: Обновление реакции - мы добавили свою к существующим
|
||||
#[test]
|
||||
fn test_update_reaction_we_add_ours() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Изначально: 2 человека, но не мы
|
||||
let msg_before = TestMessageBuilder::new("Update", 100)
|
||||
.reaction("🔥", 2, false)
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg_before);
|
||||
|
||||
// После добавления нашей: 3 человека, в том числе мы
|
||||
let msg_after = TestMessageBuilder::new("Update", 100)
|
||||
.reaction("🔥", 3, true) // is_chosen=true теперь
|
||||
.build();
|
||||
|
||||
client.messages.insert(123, vec![msg_after]);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
let reaction = &messages[0].reactions[0];
|
||||
|
||||
assert_eq!(reaction.count, 3);
|
||||
assert_eq!(reaction.is_chosen, true);
|
||||
}
|
||||
|
||||
/// Test: Реакция с count=1 отображается только emoji
|
||||
#[test]
|
||||
fn test_single_reaction_shows_only_emoji() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg = TestMessageBuilder::new("Single", 100)
|
||||
.reaction("❤️", 1, true)
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, msg);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
let reaction = &messages[0].reactions[0];
|
||||
|
||||
assert_eq!(reaction.count, 1);
|
||||
// В UI: если count=1, показываем только emoji без цифры
|
||||
// Логика рендеринга: count > 1 ? "emoji count" : "emoji"
|
||||
}
|
||||
|
||||
/// Test: Реакции на несколько сообщений
|
||||
#[test]
|
||||
fn test_reactions_on_multiple_messages() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg1 = TestMessageBuilder::new("First", 100)
|
||||
.reaction("👍", 2, false)
|
||||
.build();
|
||||
|
||||
let msg2 = TestMessageBuilder::new("Second", 101)
|
||||
.reaction("❤️", 1, true)
|
||||
.build();
|
||||
|
||||
let msg3 = TestMessageBuilder::new("Third", 102)
|
||||
.reaction("😂", 5, false)
|
||||
.reaction("🔥", 3, true) // Две разные реакции
|
||||
.build();
|
||||
|
||||
client = client
|
||||
.with_message(123, msg1)
|
||||
.with_message(123, msg2)
|
||||
.with_message(123, msg3);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
|
||||
// Первое: 1 реакция
|
||||
assert_eq!(messages[0].reactions.len(), 1);
|
||||
assert_eq!(messages[0].reactions[0].emoji, "👍");
|
||||
|
||||
// Второе: 1 реакция
|
||||
assert_eq!(messages[1].reactions.len(), 1);
|
||||
assert_eq!(messages[1].reactions[0].emoji, "❤️");
|
||||
|
||||
// Третье: 2 реакции
|
||||
assert_eq!(messages[2].reactions.len(), 2);
|
||||
assert_eq!(messages[2].reactions[0].emoji, "😂");
|
||||
assert_eq!(messages[2].reactions[1].emoji, "🔥");
|
||||
assert_eq!(messages[2].reactions[1].is_chosen, true);
|
||||
}
|
||||
202
tests/reply_forward.rs
Normal file
202
tests/reply_forward.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
// Integration tests for reply and forward flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::TestMessageBuilder;
|
||||
use tele_tui::tdlib::{ForwardInfo, ReplyInfo};
|
||||
|
||||
/// Test: Reply создаёт сообщение с reply_to
|
||||
#[test]
|
||||
fn test_reply_creates_message_with_reply_to() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Входящее сообщение от собеседника
|
||||
let original_msg = TestMessageBuilder::new("Question?", 100)
|
||||
.sender("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, original_msg);
|
||||
|
||||
// Отвечаем на него
|
||||
let reply_id = client.send_message(123, "Answer!".to_string(), Some(100));
|
||||
|
||||
// Проверяем что ответ отправлен с reply_to
|
||||
assert_eq!(client.sent_messages().len(), 1);
|
||||
assert_eq!(client.sent_messages()[0].reply_to, Some(100));
|
||||
|
||||
// Проверяем что в списке 2 сообщения
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 2);
|
||||
assert_eq!(messages[1].id, reply_id);
|
||||
assert_eq!(messages[1].content, "Answer!");
|
||||
}
|
||||
|
||||
/// Test: Reply отображает превью оригинального сообщения
|
||||
#[test]
|
||||
fn test_reply_shows_original_preview() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём сообщение с reply info
|
||||
let reply_msg = TestMessageBuilder::new("Reply text", 101)
|
||||
.outgoing()
|
||||
.reply_to(100, "Alice", "Original")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, reply_msg);
|
||||
|
||||
// Проверяем что reply_to сохранено
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert!(messages[0].reply_to.is_some());
|
||||
|
||||
let reply = messages[0].reply_to.as_ref().unwrap();
|
||||
assert_eq!(reply.message_id, 100);
|
||||
assert_eq!(reply.sender_name, "Alice");
|
||||
assert_eq!(reply.text, "Original");
|
||||
}
|
||||
|
||||
/// Test: Отмена reply mode (Esc) - сообщение отправляется без reply_to
|
||||
#[test]
|
||||
fn test_cancel_reply_sends_without_reply_to() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Входящее сообщение
|
||||
let original = TestMessageBuilder::new("Question?", 100)
|
||||
.sender("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, original);
|
||||
|
||||
// Пользователь начал reply (r), потом отменил (Esc), затем отправил
|
||||
// Это эмулируется отправкой без reply_to
|
||||
client.send_message(123, "Regular message".to_string(), None);
|
||||
|
||||
// Проверяем что отправилось без reply_to
|
||||
assert_eq!(client.sent_messages()[0].reply_to, None);
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages[1].content, "Regular message");
|
||||
}
|
||||
|
||||
/// Test: Forward создаёт сообщение с forward_from
|
||||
#[test]
|
||||
fn test_forward_creates_message_with_forward_from() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём пересланное сообщение
|
||||
let forwarded_msg = TestMessageBuilder::new("Forwarded text", 200)
|
||||
.forwarded_from("Bob")
|
||||
.build();
|
||||
|
||||
client = client.with_message(456, forwarded_msg);
|
||||
|
||||
// Проверяем что forward_from сохранено
|
||||
let messages = client.get_messages(456);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert!(messages[0].forward_from.is_some());
|
||||
|
||||
let forward = messages[0].forward_from.as_ref().unwrap();
|
||||
assert_eq!(forward.sender_name, "Bob");
|
||||
assert!(forward.date > 0); // Дата установлена
|
||||
}
|
||||
|
||||
/// Test: Forward показывает "↪ Переслано от ..."
|
||||
/// Проверяем что у пересланного сообщения есть forward_from
|
||||
#[test]
|
||||
fn test_forward_displays_sender_name() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg = TestMessageBuilder::new("Important info", 300)
|
||||
.forwarded_from("Charlie")
|
||||
.build();
|
||||
|
||||
client = client.with_message(789, msg);
|
||||
|
||||
let messages = client.get_messages(789);
|
||||
let forward = messages[0].forward_from.as_ref().unwrap();
|
||||
|
||||
// В UI это будет отображаться как "↪ Переслано от Charlie"
|
||||
assert_eq!(forward.sender_name, "Charlie");
|
||||
}
|
||||
|
||||
/// Test: Forward в другой чат
|
||||
#[test]
|
||||
fn test_forward_to_different_chat() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Исходное сообщение в чате 123
|
||||
let original = TestMessageBuilder::new("Share this", 100)
|
||||
.sender("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, original);
|
||||
|
||||
// Пересылаем в чат 456
|
||||
let forwarded = TestMessageBuilder::new("Share this", 101)
|
||||
.forwarded_from("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(456, forwarded);
|
||||
|
||||
// Проверяем что в первом чате 1 сообщение
|
||||
assert_eq!(client.get_messages(123).len(), 1);
|
||||
|
||||
// Проверяем что во втором чате тоже 1 сообщение (пересланное)
|
||||
assert_eq!(client.get_messages(456).len(), 1);
|
||||
assert!(client.get_messages(456)[0].forward_from.is_some());
|
||||
}
|
||||
|
||||
/// Test: Reply + Forward комбинация (ответ на пересланное сообщение)
|
||||
#[test]
|
||||
fn test_reply_to_forwarded_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Пересланное сообщение
|
||||
let forwarded = TestMessageBuilder::new("Forwarded", 100)
|
||||
.forwarded_from("Bob")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, forwarded);
|
||||
|
||||
// Отвечаем на пересланное сообщение
|
||||
let reply_id = client.send_message(123, "Thanks for sharing!".to_string(), Some(100));
|
||||
|
||||
// Проверяем что reply содержит reply_to
|
||||
assert_eq!(client.sent_messages()[0].reply_to, Some(100));
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 2);
|
||||
assert_eq!(messages[1].id, reply_id);
|
||||
}
|
||||
|
||||
/// Test: Forward множества сообщений (batch forward)
|
||||
#[test]
|
||||
fn test_forward_multiple_messages() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Создаём 3 пересланных сообщения
|
||||
let msg1 = TestMessageBuilder::new("Message 1", 100)
|
||||
.forwarded_from("Alice")
|
||||
.build();
|
||||
|
||||
let msg2 = TestMessageBuilder::new("Message 2", 101)
|
||||
.forwarded_from("Alice")
|
||||
.build();
|
||||
|
||||
let msg3 = TestMessageBuilder::new("Message 3", 102)
|
||||
.forwarded_from("Alice")
|
||||
.build();
|
||||
|
||||
client = client
|
||||
.with_message(456, msg1)
|
||||
.with_message(456, msg2)
|
||||
.with_message(456, msg3);
|
||||
|
||||
// Проверяем что все 3 сообщения пересланы
|
||||
let messages = client.get_messages(456);
|
||||
assert_eq!(messages.len(), 3);
|
||||
assert!(messages[0].forward_from.is_some());
|
||||
assert!(messages[1].forward_from.is_some());
|
||||
assert!(messages[2].forward_from.is_some());
|
||||
}
|
||||
119
tests/screens.rs
Normal file
119
tests/screens.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
// Screen snapshot tests
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::app_builder::TestAppBuilder;
|
||||
use helpers::snapshot_utils::{render_to_buffer, buffer_to_string};
|
||||
use helpers::test_data::create_test_chat;
|
||||
use insta::assert_snapshot;
|
||||
use tele_tui::app::AppScreen;
|
||||
use tele_tui::tdlib::client::AuthState;
|
||||
|
||||
#[test]
|
||||
fn snapshot_loading_screen_default() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Loading)
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("loading_screen_default", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_loading_screen_with_status() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Loading)
|
||||
.status_message("Подключение к Telegram...")
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("loading_screen_with_status", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_auth_screen_phone() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Auth)
|
||||
.auth_state(AuthState::WaitPhoneNumber)
|
||||
.phone_input("+7")
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("auth_screen_phone", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_auth_screen_code() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Auth)
|
||||
.auth_state(AuthState::WaitCode)
|
||||
.code_input("1234")
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("auth_screen_code", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_auth_screen_password() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Auth)
|
||||
.auth_state(AuthState::WaitPassword)
|
||||
.password_input("pass")
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("auth_screen_password", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_main_screen_empty() {
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Main)
|
||||
.build();
|
||||
|
||||
let buffer = render_to_buffer(80, 24, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_empty", output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_main_screen_terminal_too_small() {
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
|
||||
let mut app = TestAppBuilder::new()
|
||||
.screen(AppScreen::Main)
|
||||
.with_chat(chat)
|
||||
.build();
|
||||
|
||||
// Use smaller terminal size (30x8) - below minimum 40x10
|
||||
let buffer = render_to_buffer(30, 8, |f| {
|
||||
tele_tui::ui::render(f, &mut app);
|
||||
});
|
||||
|
||||
let output = buffer_to_string(&buffer);
|
||||
assert_snapshot!("main_screen_terminal_too_small", output);
|
||||
}
|
||||
241
tests/search.rs
Normal file
241
tests/search.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
// Integration tests for search flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::{create_test_chat, TestChatBuilder, TestMessageBuilder};
|
||||
|
||||
/// Test: Поиск по чатам фильтрует по названию
|
||||
#[test]
|
||||
fn test_search_chats_by_title() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat1 = create_test_chat("Mom", 123);
|
||||
let chat2 = create_test_chat("Boss", 456);
|
||||
let chat3 = create_test_chat("Mom's Work", 789);
|
||||
|
||||
client = client.with_chats(vec![chat1, chat2, chat3]);
|
||||
|
||||
// Ищем "mom" - должно найти "Mom" и "Mom's Work"
|
||||
let query = "mom".to_lowercase();
|
||||
let filtered: Vec<_> = client
|
||||
.get_chats()
|
||||
.iter()
|
||||
.filter(|c| c.title.to_lowercase().contains(&query))
|
||||
.collect();
|
||||
|
||||
assert_eq!(filtered.len(), 2);
|
||||
assert_eq!(filtered[0].title, "Mom");
|
||||
assert_eq!(filtered[1].title, "Mom's Work");
|
||||
}
|
||||
|
||||
/// Test: Поиск по чатам фильтрует по @username
|
||||
#[test]
|
||||
fn test_search_chats_by_username() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat1 = TestChatBuilder::new("Alice", 123)
|
||||
.username("alice")
|
||||
.build();
|
||||
|
||||
let chat2 = TestChatBuilder::new("Bob", 456)
|
||||
.username("bobby")
|
||||
.build();
|
||||
|
||||
let chat3 = TestChatBuilder::new("Charlie", 789).build(); // Без username
|
||||
|
||||
client = client.with_chats(vec![chat1, chat2, chat3]);
|
||||
|
||||
// Ищем "bob" - должно найти "Bob" (@bobby)
|
||||
let query = "bob".to_lowercase();
|
||||
let filtered: Vec<_> = client
|
||||
.get_chats()
|
||||
.iter()
|
||||
.filter(|c| {
|
||||
c.title.to_lowercase().contains(&query)
|
||||
|| c.username
|
||||
.as_ref()
|
||||
.map(|u| u.to_lowercase().contains(&query))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert_eq!(filtered.len(), 1);
|
||||
assert_eq!(filtered[0].title, "Bob");
|
||||
}
|
||||
|
||||
/// Test: Пустой поисковый запрос возвращает все чаты
|
||||
#[test]
|
||||
fn test_search_empty_query_returns_all() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat1 = create_test_chat("Mom", 123);
|
||||
let chat2 = create_test_chat("Boss", 456);
|
||||
let chat3 = create_test_chat("Friend", 789);
|
||||
|
||||
client = client.with_chats(vec![chat1, chat2, chat3]);
|
||||
|
||||
// Пустой запрос
|
||||
let query = "";
|
||||
let filtered: Vec<_> = client
|
||||
.get_chats()
|
||||
.iter()
|
||||
.filter(|c| c.title.to_lowercase().contains(query))
|
||||
.collect();
|
||||
|
||||
// Все чаты проходят фильтр (пустая строка содержится в любой строке)
|
||||
assert_eq!(filtered.len(), 3);
|
||||
}
|
||||
|
||||
/// Test: Поиск внутри чата по тексту сообщений
|
||||
#[test]
|
||||
fn test_search_messages_in_chat() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg1 = TestMessageBuilder::new("Hello world", 100).build();
|
||||
let msg2 = TestMessageBuilder::new("How are you?", 101).build();
|
||||
let msg3 = TestMessageBuilder::new("Hello again", 102).build();
|
||||
|
||||
client = client.with_messages(123, vec![msg1, msg2, msg3]);
|
||||
|
||||
// Ищем "hello"
|
||||
let query = "hello".to_lowercase();
|
||||
let messages = client.get_messages(123);
|
||||
let found: Vec<_> = messages
|
||||
.iter()
|
||||
.filter(|m| m.content.to_lowercase().contains(&query))
|
||||
.collect();
|
||||
|
||||
assert_eq!(found.len(), 2);
|
||||
assert_eq!(found[0].content, "Hello world");
|
||||
assert_eq!(found[1].content, "Hello again");
|
||||
}
|
||||
|
||||
/// Test: Навигация по результатам поиска (n/N)
|
||||
#[test]
|
||||
fn test_navigate_search_results() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg1 = TestMessageBuilder::new("First match", 100).build();
|
||||
let msg2 = TestMessageBuilder::new("Second match", 101).build();
|
||||
let msg3 = TestMessageBuilder::new("Third match", 102).build();
|
||||
|
||||
client = client.with_messages(123, vec![msg1, msg2, msg3]);
|
||||
|
||||
// Ищем "match"
|
||||
let query = "match".to_lowercase();
|
||||
let messages = client.get_messages(123);
|
||||
let results: Vec<_> = messages
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, m)| m.content.to_lowercase().contains(&query))
|
||||
.collect();
|
||||
|
||||
assert_eq!(results.len(), 3);
|
||||
|
||||
// Навигация: начинаем с индекса 0
|
||||
let mut current_index = 0;
|
||||
|
||||
// n - следующий результат
|
||||
current_index = (current_index + 1) % results.len();
|
||||
assert_eq!(current_index, 1);
|
||||
assert_eq!(results[current_index].1.content, "Second match");
|
||||
|
||||
// n - ещё один
|
||||
current_index = (current_index + 1) % results.len();
|
||||
assert_eq!(current_index, 2);
|
||||
assert_eq!(results[current_index].1.content, "Third match");
|
||||
|
||||
// n - wrap around к первому
|
||||
current_index = (current_index + 1) % results.len();
|
||||
assert_eq!(current_index, 0);
|
||||
assert_eq!(results[current_index].1.content, "First match");
|
||||
|
||||
// N - предыдущий (wrap to last)
|
||||
current_index = if current_index == 0 {
|
||||
results.len() - 1
|
||||
} else {
|
||||
current_index - 1
|
||||
};
|
||||
assert_eq!(current_index, 2);
|
||||
assert_eq!(results[current_index].1.content, "Third match");
|
||||
}
|
||||
|
||||
/// Test: Поиск с учётом регистра (case-insensitive)
|
||||
#[test]
|
||||
fn test_search_case_insensitive() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg1 = TestMessageBuilder::new("HELLO", 100).build();
|
||||
let msg2 = TestMessageBuilder::new("hello", 101).build();
|
||||
let msg3 = TestMessageBuilder::new("HeLLo", 102).build();
|
||||
|
||||
client = client.with_messages(123, vec![msg1, msg2, msg3]);
|
||||
|
||||
// Ищем "hello" (lowercase)
|
||||
let query = "hello".to_lowercase();
|
||||
let messages = client.get_messages(123);
|
||||
let found: Vec<_> = messages
|
||||
.iter()
|
||||
.filter(|m| m.content.to_lowercase().contains(&query))
|
||||
.collect();
|
||||
|
||||
// Все 3 варианта должны найтись
|
||||
assert_eq!(found.len(), 3);
|
||||
}
|
||||
|
||||
/// Test: Поиск не находит ничего
|
||||
#[test]
|
||||
fn test_search_no_results() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let msg1 = TestMessageBuilder::new("Hello", 100).build();
|
||||
let msg2 = TestMessageBuilder::new("World", 101).build();
|
||||
|
||||
client = client.with_messages(123, vec![msg1, msg2]);
|
||||
|
||||
// Ищем "xyz" - не должно найтись
|
||||
let query = "xyz".to_lowercase();
|
||||
let messages = client.get_messages(123);
|
||||
let found: Vec<_> = messages
|
||||
.iter()
|
||||
.filter(|m| m.content.to_lowercase().contains(&query))
|
||||
.collect();
|
||||
|
||||
assert_eq!(found.len(), 0);
|
||||
}
|
||||
|
||||
/// Test: Отмена поиска (Esc) восстанавливает обычный режим
|
||||
#[test]
|
||||
fn test_cancel_search_restores_normal_mode() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let chat1 = create_test_chat("Mom", 123);
|
||||
let chat2 = create_test_chat("Boss", 456);
|
||||
|
||||
client = client.with_chats(vec![chat1, chat2]);
|
||||
|
||||
// Симулируем: пользователь начал поиск
|
||||
let mut is_searching = true;
|
||||
let mut search_query = "mom".to_string();
|
||||
|
||||
// Фильтруем
|
||||
let query = search_query.to_lowercase();
|
||||
let filtered: Vec<_> = client
|
||||
.get_chats()
|
||||
.iter()
|
||||
.filter(|c| c.title.to_lowercase().contains(&query))
|
||||
.collect();
|
||||
|
||||
assert_eq!(filtered.len(), 1);
|
||||
|
||||
// Пользователь нажал Esc
|
||||
is_searching = false;
|
||||
search_query.clear();
|
||||
|
||||
// После отмены видим все чаты
|
||||
let all_chats = client.get_chats();
|
||||
assert_eq!(all_chats.len(), 2);
|
||||
assert!(!is_searching);
|
||||
assert_eq!(search_query, "");
|
||||
}
|
||||
146
tests/send_message.rs
Normal file
146
tests/send_message.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
// Integration tests for send message flow
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::fake_tdclient::FakeTdClient;
|
||||
use helpers::test_data::{create_test_chat, TestMessageBuilder};
|
||||
|
||||
/// Test: Отправка текстового сообщения
|
||||
#[test]
|
||||
fn test_send_text_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
let chat = create_test_chat("Mom", 123);
|
||||
client = client.with_chat(chat);
|
||||
|
||||
// Отправляем сообщение
|
||||
let msg_id = client.send_message(123, "Hello, Mom!".to_string(), None);
|
||||
|
||||
// Проверяем что сообщение было отправлено
|
||||
assert_eq!(client.sent_messages().len(), 1);
|
||||
assert_eq!(client.sent_messages()[0].chat_id, 123);
|
||||
assert_eq!(client.sent_messages()[0].text, "Hello, Mom!");
|
||||
assert_eq!(client.sent_messages()[0].reply_to, None);
|
||||
|
||||
// Проверяем что сообщение добавилось в список
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].id, msg_id);
|
||||
assert_eq!(messages[0].content, "Hello, Mom!");
|
||||
assert_eq!(messages[0].is_outgoing, true);
|
||||
}
|
||||
|
||||
/// Test: Отправка нескольких сообщений обновляет список
|
||||
#[test]
|
||||
fn test_send_multiple_messages_updates_list() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем первое сообщение
|
||||
let msg1_id = client.send_message(123, "Message 1".to_string(), None);
|
||||
|
||||
// Отправляем второе сообщение
|
||||
let msg2_id = client.send_message(123, "Message 2".to_string(), None);
|
||||
|
||||
// Отправляем третье сообщение
|
||||
let msg3_id = client.send_message(123, "Message 3".to_string(), None);
|
||||
|
||||
// Проверяем что все 3 сообщения отслеживаются
|
||||
assert_eq!(client.sent_messages().len(), 3);
|
||||
|
||||
// Проверяем что все сообщения в списке
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 3);
|
||||
assert_eq!(messages[0].id, msg1_id);
|
||||
assert_eq!(messages[1].id, msg2_id);
|
||||
assert_eq!(messages[2].id, msg3_id);
|
||||
assert_eq!(messages[0].content, "Message 1");
|
||||
assert_eq!(messages[1].content, "Message 2");
|
||||
assert_eq!(messages[2].content, "Message 3");
|
||||
}
|
||||
|
||||
/// Test: Отправка пустого сообщения (должно быть игнорировано на уровне App)
|
||||
/// Здесь мы тестируем что FakeTdClient технически может отправить пустое сообщение,
|
||||
/// но в реальном App это должно фильтроваться
|
||||
#[test]
|
||||
fn test_send_empty_message_technical() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// FakeTdClient технически может отправить пустое сообщение
|
||||
let msg_id = client.send_message(123, "".to_string(), None);
|
||||
|
||||
// Проверяем что оно отправилось (в реальном App это должно фильтроваться)
|
||||
assert_eq!(client.sent_messages().len(), 1);
|
||||
assert_eq!(client.sent_messages()[0].text, "");
|
||||
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].id, msg_id);
|
||||
assert_eq!(messages[0].content, "");
|
||||
}
|
||||
|
||||
/// Test: Отправка сообщения с форматированием (markdown сущности)
|
||||
/// В данном случае мы не проверяем парсинг markdown, только что текст сохраняется
|
||||
#[test]
|
||||
fn test_send_message_with_markdown() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
let text = "**Bold** *italic* `code`";
|
||||
client.send_message(123, text.to_string(), None);
|
||||
|
||||
// Проверяем что текст сохранился как есть (парсинг markdown - отдельная логика)
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 1);
|
||||
assert_eq!(messages[0].content, text);
|
||||
}
|
||||
|
||||
/// Test: Отправка сообщения в разные чаты
|
||||
#[test]
|
||||
fn test_send_messages_to_different_chats() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Отправляем в чат 123
|
||||
client.send_message(123, "Hello Mom".to_string(), None);
|
||||
|
||||
// Отправляем в чат 456
|
||||
client.send_message(456, "Hello Boss".to_string(), None);
|
||||
|
||||
// Отправляем ещё одно в чат 123
|
||||
client.send_message(123, "How are you?".to_string(), None);
|
||||
|
||||
// Проверяем общее количество отправленных
|
||||
assert_eq!(client.sent_messages().len(), 3);
|
||||
|
||||
// Проверяем что сообщения распределены по чатам
|
||||
let chat123_messages = client.get_messages(123);
|
||||
assert_eq!(chat123_messages.len(), 2);
|
||||
assert_eq!(chat123_messages[0].content, "Hello Mom");
|
||||
assert_eq!(chat123_messages[1].content, "How are you?");
|
||||
|
||||
let chat456_messages = client.get_messages(456);
|
||||
assert_eq!(chat456_messages.len(), 1);
|
||||
assert_eq!(chat456_messages[0].content, "Hello Boss");
|
||||
}
|
||||
|
||||
/// Test: Новое сообщение появляется в реальном времени (симуляция)
|
||||
/// Тестируем что когда приходит новое входящее сообщение, оно добавляется в список
|
||||
#[test]
|
||||
fn test_receive_incoming_message() {
|
||||
let mut client = FakeTdClient::new();
|
||||
|
||||
// Добавляем существующее сообщение
|
||||
client.send_message(123, "My outgoing".to_string(), None);
|
||||
|
||||
// Симулируем входящее сообщение от собеседника
|
||||
let incoming_msg = TestMessageBuilder::new("Hey there!", 2000)
|
||||
.sender("Alice")
|
||||
.build();
|
||||
|
||||
client = client.with_message(123, incoming_msg);
|
||||
|
||||
// Проверяем что в списке 2 сообщения
|
||||
let messages = client.get_messages(123);
|
||||
assert_eq!(messages.len(), 2);
|
||||
assert_eq!(messages[0].is_outgoing, true); // Наше сообщение
|
||||
assert_eq!(messages[1].is_outgoing, false); // Входящее
|
||||
assert_eq!(messages[1].content, "Hey there!");
|
||||
assert_eq!(messages[1].sender_name, "Alice");
|
||||
}
|
||||
5
tests/snapshots/footer__footer_chat_list.snap
Normal file
5
tests/snapshots/footer__footer_chat_list.snap
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/footer.rs
|
||||
expression: output
|
||||
---
|
||||
⏳ Подключение... | Инициализация TDLib...
|
||||
5
tests/snapshots/footer__footer_network_connecting.snap
Normal file
5
tests/snapshots/footer__footer_network_connecting.snap
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/footer.rs
|
||||
expression: output
|
||||
---
|
||||
⏳ Подключение... | Инициализация TDLib...
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/footer.rs
|
||||
expression: output
|
||||
---
|
||||
⏳ Прокси... | Инициализация TDLib...
|
||||
5
tests/snapshots/footer__footer_network_waiting.snap
Normal file
5
tests/snapshots/footer__footer_network_waiting.snap
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/footer.rs
|
||||
expression: output
|
||||
---
|
||||
⚠ Нет сети | Инициализация TDLib...
|
||||
5
tests/snapshots/footer__footer_open_chat.snap
Normal file
5
tests/snapshots/footer__footer_open_chat.snap
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/footer.rs
|
||||
expression: output
|
||||
---
|
||||
⏳ Подключение... | Инициализация TDLib...
|
||||
5
tests/snapshots/footer__footer_search_mode.snap
Normal file
5
tests/snapshots/footer__footer_search_mode.snap
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/footer.rs
|
||||
expression: output
|
||||
---
|
||||
⏳ Подключение... | Инициализация TDLib...
|
||||
28
tests/snapshots/input_field__empty_input.snap
Normal file
28
tests/snapshots/input_field__empty_input.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│👤 Mom │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│Нет сообщений │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│> █ Введите сообщение... │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/input_field__input_editing_mode.snap
Normal file
28
tests/snapshots/input_field__input_editing_mode.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│👤 Mom │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ──────── 02.01.2022 ──────── │
|
||||
│ │
|
||||
│ Вы ──────────────── │
|
||||
│ Original message text (14:33 ✓✓) │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌ Редактирование (Esc отмена) ─────────────────────────────────────────────────┐
|
||||
│✏ Edited text here │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/input_field__input_long_text_2_lines.snap
Normal file
28
tests/snapshots/input_field__input_long_text_2_lines.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│👤 Mom │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│Нет сообщений │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│> This is a longer message that will wrap to multiple lines in the input field│
|
||||
│for testing purposes. │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/input_field__input_long_text_max_lines.snap
Normal file
28
tests/snapshots/input_field__input_long_text_max_lines.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│👤 Mom │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│Нет сообщений │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod │
|
||||
│tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, │
|
||||
│quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo │
|
||||
│consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse │
|
||||
│cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non │
|
||||
│proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed │
|
||||
│ut perspiciatis unde omnis iste natus error sit voluptatem accusantium │
|
||||
│doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/input_field__input_reply_mode.snap
Normal file
28
tests/snapshots/input_field__input_reply_mode.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│👤 Mom │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ──────── 02.01.2022 ──────── │
|
||||
│ │
|
||||
│Mom ──────────────── │
|
||||
│ (14:33) What do you think about this? │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌ Ответ (Esc отмена) ──────────────────────────────────────────────────────────┐
|
||||
│↪ Mom: What do yo > I think it's great! │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/input_field__input_search_mode.snap
Normal file
28
tests/snapshots/input_field__input_search_mode.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│🔍 hello │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/input_field__input_with_text.snap
Normal file
28
tests/snapshots/input_field__input_with_text.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/input_field.rs
|
||||
expression: output
|
||||
---
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│👤 Mom │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│Нет сообщений │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│> Hello, how are you? │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
22
tests/snapshots/screens__auth_screen_code.snap
Normal file
22
tests/snapshots/screens__auth_screen_code.snap
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
┌──────────────────────────────────────┐
|
||||
│ TTUI - Telegram Authentication │
|
||||
└──────────────────────────────────────┘
|
||||
Введите код подтверждения из Telegram
|
||||
Код был отправлен на ваш номер
|
||||
|
||||
|
||||
┌ Verification Code ───────────────────┐
|
||||
│ 🔐 1234 │
|
||||
└──────────────────────────────────────┘
|
||||
Инициализация TDLib...
|
||||
22
tests/snapshots/screens__auth_screen_password.snap
Normal file
22
tests/snapshots/screens__auth_screen_password.snap
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
┌──────────────────────────────────────┐
|
||||
│ TTUI - Telegram Authentication │
|
||||
└──────────────────────────────────────┘
|
||||
Введите пароль двухфакторной аутентифика
|
||||
|
||||
|
||||
|
||||
┌ Password ────────────────────────────┐
|
||||
│ 🔒 **** │
|
||||
└──────────────────────────────────────┘
|
||||
Инициализация TDLib...
|
||||
22
tests/snapshots/screens__auth_screen_phone.snap
Normal file
22
tests/snapshots/screens__auth_screen_phone.snap
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
┌──────────────────────────────────────┐
|
||||
│ TTUI - Telegram Authentication │
|
||||
└──────────────────────────────────────┘
|
||||
Введите номер телефона в международном ф
|
||||
Пример: +79991111111
|
||||
|
||||
|
||||
┌ Phone Number ────────────────────────┐
|
||||
│ 📱 +7 │
|
||||
└──────────────────────────────────────┘
|
||||
Инициализация TDLib...
|
||||
18
tests/snapshots/screens__loading_screen_default.snap
Normal file
18
tests/snapshots/screens__loading_screen_default.snap
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
┌ TTUI ────────────────────────────────────────────────────────────────────────┐
|
||||
│ Инициализация TDLib... │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
18
tests/snapshots/screens__loading_screen_with_status.snap
Normal file
18
tests/snapshots/screens__loading_screen_with_status.snap
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
┌ TTUI ────────────────────────────────────────────────────────────────────────┐
|
||||
│ Подключение к Telegram... │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
28
tests/snapshots/screens__main_screen_empty.snap
Normal file
28
tests/snapshots/screens__main_screen_empty.snap
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
┌ TTUI ────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1:All │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
┌──────────────────────┐┌──────────────────────────────────────────────────────┐
|
||||
│🔍 Ctrl+S для поиска ││ Выберите чат │
|
||||
└──────────────────────┘│ │
|
||||
┌──────────────────────┐│ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
│ ││ │
|
||||
└──────────────────────┘│ │
|
||||
┌──────────────────────┐│ │
|
||||
│ ││ │
|
||||
└──────────────────────┘└──────────────────────────────────────────────────────┘
|
||||
⏳ Подключение... | Инициализация TDLib...
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: tests/screens.rs
|
||||
expression: output
|
||||
---
|
||||
30x8
|
||||
Минимум: 40x10
|
||||
Reference in New Issue
Block a user