import bot def _state(uid): return bot.db.get_user_data(uid)["state"] def _prof(uid): return bot.db.get_profile(uid) def test_baza_group_funnel_to_payment(app): """Полный подбор → групповой абонемент → шаг оплаты (BAZA_PAY).""" u = 70001 app.handle_message(u, "Подобрать тренировку 🎯"); assert _state(u) == "BAZA_FORWHO" app.handle_message(u, "Для подростка"); assert _state(u) == "BAZA_AGE" app.handle_message(u, "14–15 лет"); assert _state(u) == "BAZA_GAME" app.handle_message(u, "CS2"); assert _state(u) == "BAZA_LEVEL" app.handle_message(u, "Играет для себя"); assert _state(u) == "BAZA_FORMAT" app.handle_message(u, "Групповые тренировки"); assert _state(u) == "BAZA_GROUP" app.handle_message(u, "Купить 4 тренировки"); assert _state(u) == "BAZA_PAY" p = _prof(u) assert p["role"].startswith("Родитель") and p["game"] == "CS2" assert p["format"] == "Групповые тренировки" and "4" in p["tariff"] assert p.get("started_at") # дата запуска сохранена (§13) assert {"role_parent", "game_cs2", "format_group", "clicked_payment", "lead_hot"} <= set(p["metki"]) def test_baza_individual_and_back(app): """Индивидуальная ветка + кнопка «Назад» возвращает на предыдущий шаг.""" u = 70011 app.handle_message(u, "Подобрать тренировку 🎯") app.handle_message(u, "Для себя"); assert _state(u) == "BAZA_AGE" app.handle_message(u, "16 лет и старше"); assert _state(u) == "BAZA_GAME" app.handle_message(u, "Назад ⬅️"); assert _state(u) == "BAZA_AGE" app.handle_message(u, "16 лет и старше") app.handle_message(u, "Dota 2"); assert _state(u) == "BAZA_LEVEL" app.handle_message(u, "Есть рейтинг или ранг") app.handle_message(u, "Индивидуальные тренировки"); assert _state(u) == "BAZA_INDIVIDUAL" app.handle_message(u, "Купить 8 тренировок"); assert _state(u) == "BAZA_PAY" assert "8" in _prof(u)["tariff"] def test_baza_under12_goes_to_manager(app): u = 70012 app.handle_message(u, "Подобрать тренировку 🎯") app.handle_message(u, "Для подростка") app.handle_message(u, "Младше 12 лет"); assert _state(u) == "BAZA_YOUNG" app.handle_message(u, "Обсудить с менеджером 💬") assert _state(u) == "OPERATOR_CHAT" assert _prof(u)["age"] == "Младше 12 лет" assert "manager_requested" in _prof(u)["metki"] def test_baza_other_game_goes_to_manager(app): u = 70013 app.handle_message(u, "Подобрать тренировку 🎯") app.handle_message(u, "Для себя") app.handle_message(u, "16 лет и старше") app.handle_message(u, "Другая игра"); assert _state(u) == "BAZA_GAME_OTHER" app.handle_message(u, "Valorant"); assert _state(u) == "OPERATOR_CHAT" assert "Valorant" in _prof(u)["game"] def test_baza_intensive_by_keyword(app): """Кодовое слово «лето» запускает интенсив; ветка доходит до оплаты.""" u = 70014 app.handle_message(u, "лето"); assert _state(u) == "BAZA_INT_INFO" app.handle_message(u, "Хочу участвовать 🔥"); assert _state(u) == "BAZA_INT_AGE" app.handle_message(u, "14–15 лет"); assert _state(u) == "BAZA_INT_LEVEL" app.handle_message(u, "Играю регулярно"); assert _state(u) == "BAZA_INT_PAY_INTRO" app.handle_message(u, "Оплатить интенсив 💳"); assert _state(u) == "BAZA_PAY" p = _prof(u) assert p["keyword"] == "лето" and p.get("interest_summer") assert {"source_keyword_summer", "interest_summer_intensive", "clicked_payment"} <= set(p["metki"]) def test_baza_under12_intensive_to_manager(app): u = 70017 app.handle_message(u, "Летний интенсив CS2 🔥") app.handle_message(u, "Хочу участвовать 🔥") app.handle_message(u, "Младше 12 лет"); assert _state(u) == "BAZA_INT_YOUNG" app.handle_message(u, "Передать менеджеру 💬"); assert _state(u) == "OPERATOR_CHAT" def test_baza_question_button_handoff(app): """«Задать вопрос» (§9): сначала промпт, затем сообщение → менеджеру.""" u = 70015 app.handle_message(u, "Задать вопрос 💬"); assert _state(u) == "BAZA_QUESTION" app.handle_message(u, "Когда занятия?"); assert _state(u) == "OPERATOR_CHAT" assert _prof(u)["message"] == "Когда занятия?" assert "manager_requested" in _prof(u)["metki"] def test_baza_help_free_text_to_manager(app): """§7: «Пока не знаю» → свободный текст → менеджеру, format_help.""" u = 70018 app.handle_message(u, "Подобрать тренировку 🎯") app.handle_message(u, "Для себя") app.handle_message(u, "14–15 лет") app.handle_message(u, "CS2") app.handle_message(u, "Только начинает") app.handle_message(u, "Пока не знаю, нужен совет"); assert _state(u) == "BAZA_HELP" app.handle_message(u, "важно расписание"); assert _state(u) == "OPERATOR_CHAT" assert _prof(u)["message"] == "важно расписание" assert "format_help" in _prof(u)["metki"] def test_baza_prices_and_menu(app): u = 70016 app._sent.clear() app.handle_message(u, "Посмотреть цены 💰") assert _state(u) == "FREE_CHAT" assert any("2 790" in s["msg"] for s in app._sent) def test_flood_does_not_crash(app): u = 70002 for _ in range(25): app.handle_message(u, "спам") # бот не падает; пользователь остаётся в FREE_CHAT (флуд/бан только игнорят) assert _state(u) == "FREE_CHAT" def test_admin_panel_visible_to_super(app): admin = bot.config.SUPER_ADMIN_IDS[0] app._sent.clear() app.handle_message(admin, "Админка ⚙️") assert any("Статистика" in (s["kb"] or "") for s in app._sent) def test_non_admin_cannot_open_panel(app): app._sent.clear() app.handle_message(424242, "Админка ⚙️") assert not any("Админ-панель" in s["msg"] for s in app._sent) def _admin(): return bot.config.SUPER_ADMIN_IDS[0] def test_admin_faq_crud(app): a = _admin() app.handle_message(a, "Быстрые ответы 💬") app.handle_message(a, "➕ Добавить ответ") app.handle_message(a, "вопрос | ответ") assert any(kw == "вопрос" for _, kw, _ in bot.db.get_custom_faq()) def test_admin_add_remove_admin(app): a = _admin() app.handle_message(a, "Администраторы 👑") app.handle_message(a, "➕ Добавить админа") app.handle_message(a, "888001") assert 888001 in bot.db.get_admins() assert app._is_admin(888001) def test_broadcast_preview_and_cancel(app): a = _admin() app.handle_message(a, "рассылка Привет, акция!") assert a in app._pending_broadcasts app.handle_message(a, "Отмена ❌") assert a not in app._pending_broadcasts def test_stats_runs(app): a = _admin() app._sent.clear() app.handle_message(a, "Статистика 📊") assert any("Статистика" in s["msg"] for s in app._sent)