Files
telegram-tui/TESTING_ROADMAP.md
Mikhail Kilin c5896b7f14 tests
2026-01-31 23:02:53 +03:00

21 KiB
Raw Blame History

Testing Roadmap

План покрытия tele-tui тестами с фокусом на интеграционные и e2e тесты.

Стратегия тестирования

Подход: Комбо (Snapshot + Integration + E2E)

  1. Snapshot Testing (70%) — проверка UI рендеринга через insta
  2. Integration Testing (25%) — проверка логики и flow через FakeTdClient
  3. E2E Smoke Testing (5%) — базовая проверка что приложение запускается

Почему не юнит-тесты?

  • TUI сложно тестировать через юниты (моки, хрупкость)
  • Интеграционные тесты дают больше уверенности
  • Snapshots ловят UI регрессии лучше, чем assert координат

Фаза 0: Инфраструктура

Зависимости

  • Добавить insta = "1.34" в dev-dependencies
  • Добавить tokio-test = "0.4" в dev-dependencies
  • Настроить .gitignore для snapshots (добавить tests/snapshots/*.new)

Helpers и Test Utilities

  • Создать tests/helpers/mod.rs
  • Создать tests/helpers/app_builder.rs — builder для тестового App
  • Создать tests/helpers/fake_tdclient.rs — mock TDLib клиент
  • Создать tests/helpers/snapshot_utils.rs — утилиты для snapshot тестов
  • Создать tests/helpers/test_data.rs — фикстуры данных (чаты, сообщения)
// tests/helpers/mod.rs
pub mod app_builder;
pub mod fake_tdclient;
pub mod snapshot_utils;
pub mod test_data;

pub use app_builder::TestAppBuilder;
pub use fake_tdclient::FakeTdClient;
pub use snapshot_utils::{render_to_string, assert_ui_snapshot};
pub use test_data::{create_test_chat, create_test_message};

Файлы для создания:

tests/
├── helpers/
│   ├── mod.rs
│   ├── app_builder.rs
│   ├── fake_tdclient.rs
│   ├── snapshot_utils.rs
│   └── test_data.rs
└── snapshots/           # Создаётся insta автоматически

Фаза 1: Snapshot Tests для UI (Приоритет: ВЫСОКИЙ)

1.1 Chat List — Список чатов

Файл: tests/ui/chat_list_test.rs

  • Пустой список чатов
  • Список с 3 чатами (без индикаторов)
  • Чат с непрочитанными сообщениями (5)
  • Чат с иконкой закреплённого 📌
  • Чат с иконкой mute 🔇
  • Чат с индикатором mention @
  • Чат с онлайн-статусом ●
  • Выбранный чат (с ▌)
  • Список чатов в режиме поиска
  • Длинное название чата (обрезка)

Пример теста:

#[test]
fn snapshot_chat_list_with_unread() {
    let app = TestAppBuilder::new()
        .with_chat(create_test_chat("Mom", 123, unread: 5))
        .with_chat(create_test_chat("Boss", 456, unread: 0))
        .build();

    assert_ui_snapshot!("chat_list_with_unread", app, |f, app| {
        render_chat_list(f, f.size(), app);
    });
}

1.2 Messages — Область сообщений

Файл: tests/messages.rs

  • Пустой чат (нет сообщений)
  • Одно входящее сообщение
  • Одно исходящее сообщение
  • Группировка по дате (разделитель "Сегодня")
  • Группировка по дате (разделитель "Вчера")
  • Группировка по отправителю (заголовок с именем)
  • Исходящее сообщение с ✓ (отправлено)
  • Исходящее сообщение с ✓✓ (прочитано)
  • Сообщение с индикатором редактирования ✎
  • Длинное сообщение (wrap на несколько строк)
  • Markdown: жирный, курсив, код
  • Markdown: ссылка, упоминание
  • Markdown: спойлер
  • Сообщение с медиа-заглушкой [Фото]
  • Reply сообщение с превью
  • Пересланное сообщение (↪ Переслано от)
  • Сообщение с одной реакцией [👍]
  • Сообщение с несколькими реакциями [👍] 5 👎 3
  • Выбранное сообщение (подсветка)

1.3 Modals — Модальные окна

Файл: tests/modals.rs

  • Delete confirmation модалка
  • Emoji picker (8x6 сетка)
  • Emoji picker с выбранной реакцией (курсор)
  • Profile модалка (личный чат)
  • Profile модалка (группа)
  • Pinned message вверху чата
  • Search в чате (с результатами)
  • Forward mode (список чатов для пересылки)

1.4 Input Field — Поле ввода

Файл: tests/input_field.rs

  • Пустое поле ввода
  • Поле ввода с текстом и курсором █
  • Поле ввода с длинным текстом (2 строки)
  • Поле ввода с длинным текстом (10 строк, максимум)
  • Режим редактирования (с превью)
  • Режим reply (с превью сообщения)
  • Режим поиска (с query)

Файл: tests/footer.rs

  • Footer в списке чатов (команды навигации)
  • Footer в открытом чате (команды сообщений)
  • Footer с индикатором "⚠ Нет сети"
  • Footer с индикатором " Подключение к прокси..."
  • Footer с индикатором " Подключение..."
  • Footer в режиме поиска

1.6 Screens — Полные экраны

Файл: tests/screens.rs

  • Loading screen (default)
  • Loading screen (со статусом)
  • Auth screen (ввод телефона)
  • Auth screen (ввод кода)
  • Auth screen (ввод пароля 2FA)
  • Main screen (пустой список чатов)
  • Минимальный размер терминала (предупреждение)

Фаза 2: Integration Tests для логики (Приоритет: ВЫСОКИЙ)

2.1 Send Message Flow

Файл: tests/send_message.rs (6 тестов)

  • Отправка текстового сообщения
  • Отправка нескольких сообщений
  • Отправка с markdown форматированием
  • Отправка в разные чаты
  • Получение входящего сообщения
  • Отправка с reply

2.2 Edit Message Flow

Файл: tests/edit_message.rs (6 тестов)

  • Редактирование текста сообщения
  • Установка edit_date после редактирования
  • Проверка can_be_edited перед редактированием
  • Редактирование только своих сообщений
  • Множественные редактирования
  • Редактирование с форматированием

2.3 Delete Message Flow

Файл: tests/delete_message.rs (6 тестов)

  • Удаление сообщения из списка
  • Множественные удаления
  • Проверка can_be_deleted
  • Удаление только своих сообщений
  • Удаление из разных чатов
  • Delete with revoke

2.4 Reply & Forward Flow

Файл: tests/reply_forward.rs (8 тестов)

  • Reply на сообщение с превью
  • Reply сохраняет связь с оригиналом
  • Forward сообщения
  • Forward с sender_name
  • Forward в разные чаты
  • Reply + Forward комбо
  • Reply на forwarded сообщение
  • Forward reply сообщения

2.5 Reactions Flow

Файл: tests/reactions.rs (10 тестов)

  • Добавление реакции на сообщение
  • Удаление реакции (toggle)
  • Множественные реакции на одно сообщение
  • Реакции от разных пользователей
  • Подсчёт реакций
  • Chosen реакция (своя)
  • Реакции обновляются в реальном времени
  • Получение доступных реакций чата
  • Реакции на forwarded сообщения
  • Очистка всех реакций

2.6 Search Flow

Файл: tests/search.rs (8 тестов)

  • Поиск по названию чата
  • Поиск по @username
  • Поиск по сообщениям в чате
  • Навигация по результатам поиска
  • Case-insensitive поиск
  • Поиск с пробелами
  • Поиск возвращает пустой список если нет совпадений
  • Очистка поиска

2.7 Drafts Flow

Файл: tests/drafts.rs (7 тестов)

  • Сохранение черновика при переключении чатов
  • Восстановление черновика при возврате
  • Удаление черновика после отправки
  • Черновики для разных чатов независимы
  • Индикатор черновика в списке чатов
  • Пустой черновик не сохраняется
  • Черновик сохраняется при закрытии чата

2.8 Navigation Flow

Файл: tests/navigation.rs (7 тестов)

  • Навигация по списку чатов (↑/↓)
  • Открытие чата (Enter)
  • Закрытие чата (Esc)
  • Скролл сообщений (↑/↓)
  • Переключение между папками (1-9)
  • Навигация с wrap (переход с конца на начало)
  • Навигация в пустом списке

2.9 Profile Flow

Файл: tests/profile.rs (6 тестов)

  • Открытие профиля личного чата
  • Профиль показывает имя и username
  • Профиль показывает телефон
  • Открытие профиля группы
  • Профиль группы показывает участников
  • Закрытие профиля (Esc)

2.10 Network & Typing Flow

Файл: tests/network_typing.rs (9 тестов)

  • Typing indicator при наборе текста
  • Отправка typing action
  • Получение typing статуса
  • Typing timeout
  • Network state: WaitingForNetwork
  • Network state: ConnectingToProxy
  • Network state: Connecting
  • Network state: Updating
  • Network state: Ready

2.11 Copy Flow

Файл: tests/copy.rs (9 тестов - ПРЕВЗОШЛИ ПЛАН!)

  • Форматирование простого сообщения
  • Форматирование с forward контекстом
  • Форматирование с reply контекстом
  • Форматирование с forward + reply одновременно
  • Форматирование длинного сообщения
  • Форматирование с markdown entities
  • Clipboard initialization
  • Копирование в реальный clipboard (ручное)
  • Кроссплатформенность clipboard

2.12 Config Flow

Файл: tests/config.rs (11 тестов - ПРЕВЗОШЛИ ПЛАН!)

  • Дефолтные значения конфигурации
  • Кастомные значения конфигурации
  • Парсинг валидных цветов
  • Парсинг light цветов
  • Парсинг невалидного цвета с fallback
  • Case-insensitive парсинг цветов
  • TOML сериализация и десериализация
  • Частичный TOML использует дефолты
  • Различные форматы timezone
  • Загрузка credentials из переменных окружения
  • Проверка формата ошибки когда credentials не найдены

Фаза 3: E2E Integration Tests (Приоритет: СРЕДНИЙ)

3.1 Smoke Tests

Файл: tests/e2e_smoke.rs (4 теста)

  • Приложение запускается без краша
  • Проверка минимального размера терминала
  • Базовые константы приложения
  • Graceful shutdown флаг

3.2 User Journey Tests

Файл: tests/e2e_user_journey.rs (8 тестов)

  • App Launch → Auth → Chat List
  • Open Chat → Load History → Send Message
  • Receive Incoming Message While Chat Open
  • Multi-step conversation flow
  • Switch between chats
  • Edit message in conversation flow
  • Reply to message in conversation
  • Network state changes during conversation

Итого: 12/12 E2E тестов (100%)

Примечание: Все тесты используют FakeTdClient для полной симуляции TDLib без реального подключения.


Фаза 4: Дополнительные тесты (Приоритет: НИЗКИЙ)

4.1 Utils Tests

Файл: tests/unit/utils_test.rs

  • format_timestamp_with_tz с разными timezone
  • parse_timezone_offset валидные значения
  • parse_timezone_offset инвалидные значения (fallback)
  • format_date для сегодня, вчера, старых дат
  • format_was_online для разных временных промежутков

4.2 Performance Tests

Файл: tests/performance/render_bench.rs

  • Benchmark рендеринга 100 сообщений
  • Benchmark рендеринга списка 50 чатов
  • Benchmark форматирования markdown текста

Метрики прогресса

Фаза 0: Инфраструктура

  • 8/8 задач выполнено

Фаза 1: Snapshot Tests

  • 1.1 Chat List: 10/10 (100%)
  • 1.2 Messages: 19/19 (100%)
  • 1.3 Modals: 8/8 (100%)
  • 1.4 Input Field: 7/7 (100%)
  • 1.5 Footer: 6/6 (100%)
  • 1.6 Screens: 7/7 (100%)
  • Итого: 57/57 snapshot тестов (100%)

Фаза 2: Integration Tests

  • 2.1 Send Message: 6/6
  • 2.2 Edit Message: 6/6
  • 2.3 Delete Message: 6/6
  • 2.4 Reply & Forward: 8/8
  • 2.5 Reactions: 10/10
  • 2.6 Search: 8/8
  • 2.7 Drafts: 7/7
  • 2.8 Navigation: 7/7
  • 2.9 Profile: 6/6
  • 2.10 Network & Typing: 9/9
  • 2.11 Copy: 9/9 (вместо 3!)
  • 2.12 Config: 11/11 (вместо 8!)
  • Итого: 93/93 интеграционных тестов (100%!) — ПРЕВЗОШЛИ ПЛАН! 🎉

Фаза 3: E2E Integration

  • 3.1 Smoke Tests: 4/4
  • 3.2 User Journey: 8/8
  • Итого: 12/12 E2E тестов (100%)

Фаза 4: Дополнительно

  • 4.1 Utils: 0/5
  • 4.2 Performance: 0/3
  • Итого: 0/8 дополнительных тестов

Общий прогресс

Всего: 164/171 тестов (96%) — ПРЕВЗОШЛИ ПЛАН! 🎉🎉🎉

Фаза 0 (Инфраструктура): Завершена (100%) Фаза 1 (UI Snapshot Tests): 57/57 (100%) — ЗАВЕРШЕНА! 🎉

  • 1.1 Chat List: 10/10 (включая онлайн-статус)
  • 1.2 Messages: 19/19
  • 1.3 Modals: 8/8
  • 1.4 Input Field: 7/7
  • 1.5 Footer: 6/6
  • 1.6 Screens: 7/7

Фаза 2 (Integration Tests): 93/93 (100%!) — ПРЕВЗОШЛИ ПЛАН!

  • Завершено: 2.1-2.12
  • Превзошли план на 9 тестов: Copy (9 вместо 3), Config (11 вместо 8)

Фаза 3 (E2E Integration Tests): 12/12 (100%) — ЗАВЕРШЕНА! 🎉

  • Smoke Tests: 4/4
  • User Journey: 8/8

Опционально:

  • Фаза 4 (Utils + Performance): 0/8

Приоритизация

Критичные (делать в первую очередь):

  1. Фаза 0: Инфраструктура (без неё никуда)
  2. 1.2: Messages snapshots (ядро приложения)
  3. 2.1: Send message (основной flow)
  4. 2.8: Navigation (базовая навигация)

Важные (делать после критичных):

  1. 1.1: Chat list snapshots
  2. 2.2: Edit message
  3. 2.3: Delete message
  4. 2.5: Reactions
  5. 2.6: Search

Желательные (можно отложить):

  1. 1.3-1.6: Остальные snapshots
  2. 2.4, 2.7, 2.9-2.12: Остальные flows
  3. Фаза 3: E2E smoke tests

Опциональные (по желанию):

  1. Фаза 4: Utils и performance

Технологии

Основные

  • insta — snapshot testing
  • tokio-test — async testing utilities
  • ratatui::backend::TestBackend — виртуальный терминал

Дополнительные (опционально)

  • expectrl — для E2E тестов с реальным бинарником
  • criterion — для бенчмарков (фаза 4.2)
  • mockall — если понадобятся моки (скорее всего нет)

Примеры структуры тестов

Snapshot Test

use insta::assert_snapshot;
use ratatui::backend::TestBackend;
use ratatui::Terminal;

#[test]
fn snapshot_messages_with_reactions() {
    let mut terminal = Terminal::new(TestBackend::new(80, 24)).unwrap();

    let app = TestAppBuilder::new()
        .with_message(create_test_message("Hello!", reactions: vec![
            reaction("👍", 1, chosen: true),
            reaction("👎", 3, chosen: false),
        ]))
        .build();

    terminal.draw(|f| {
        render_messages(f, f.size(), &app);
    }).unwrap();

    let buffer = terminal.backend().buffer();
    assert_snapshot!(buffer_to_string(buffer));
}

Integration Test

use crate::helpers::{TestAppBuilder, FakeTdClient};

#[tokio::test]
async fn test_send_message_updates_ui() {
    let fake_client = FakeTdClient::new()
        .with_chat("Mom", 123);

    let mut app = TestAppBuilder::new()
        .with_client(fake_client)
        .with_selected_chat(123)
        .build();

    // Ввод текста
    app.input_text = "Hello!".to_string();

    // Отправка
    app.handle_key(KeyCode::Enter).await;

    // Проверки
    assert_eq!(app.input_text, ""); // Инпут очистился
    assert_eq!(app.current_messages().len(), 1);
    assert_eq!(app.current_messages()[0].text, "Hello!");
    assert_eq!(fake_client.sent_messages().len(), 1);
}

Команды

# Прогнать все тесты
cargo test

# Прогнать только snapshot тесты
cargo test --test ui

# Прогнать только integration тесты
cargo test --test integration

# Обновить snapshots (после ревью изменений)
cargo insta review

# Принять все новые snapshots
cargo insta accept

# Показать diff для изменённых snapshots
cargo insta test --review

Правила

  1. Один тест = один сценарий — не делать мега-тесты
  2. Snapshots коммитим — они часть тестов
  3. Фикстуры переиспользуем — общие данные в test_data.rs
  4. Тесты изолированы — каждый тест создаёт свой App
  5. Порядок не важен — тесты можно запускать в любом порядке

TODO перед началом

  • Прочитать документацию insta: https://insta.rs/
  • Решить: нужен ли trait для TdClient или достаточно FakeTdClient
  • Обсудить: какие тесты делать в первую очередь

Примечания

  • Этот документ будет обновляться по мере написания тестов
  • После завершения фазы — отмечать в метриках
  • Если тест падает или не актуален — документировать причину
  • Snapshots хранятся в tests/snapshots/__snapshots__/