v2.0
This commit is contained in:
472
tests/test_panel_ui.py
Normal file
472
tests/test_panel_ui.py
Normal file
@@ -0,0 +1,472 @@
|
||||
from datetime import datetime, timedelta
|
||||
from types import SimpleNamespace
|
||||
|
||||
from app.bot.ui.panel import (
|
||||
PANEL_SECTION_ADMIN,
|
||||
PANEL_SECTION_HOME,
|
||||
PANEL_SECTION_REFERRAL,
|
||||
PANEL_SECTION_SUBSCRIPTION,
|
||||
PANEL_SECTION_SUPPORT,
|
||||
PANEL_SECTION_TERMS,
|
||||
PanelContext,
|
||||
build_panel_keyboard,
|
||||
render_panel_caption,
|
||||
)
|
||||
from app.services.sync_service import CachedUserView
|
||||
|
||||
|
||||
def _button_texts(markup) -> list[str]:
|
||||
return [button.text for row in markup.inline_keyboard for button in row]
|
||||
|
||||
|
||||
def _cached_user_view(*, telegram_id: int = 123456789) -> CachedUserView:
|
||||
return CachedUserView(
|
||||
record=SimpleNamespace(
|
||||
username="oreol-renew",
|
||||
status="ACTIVE",
|
||||
expire_at=datetime.now() + timedelta(days=10),
|
||||
used_traffic_bytes=0,
|
||||
traffic_limit_bytes=0,
|
||||
short_uuid="renew999",
|
||||
subscription_url="https://example.com/sub/renew999",
|
||||
telegram_id=telegram_id,
|
||||
),
|
||||
internal_squads=["VPN"],
|
||||
)
|
||||
|
||||
|
||||
def test_home_panel_caption_without_subscription() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_HOME,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "Добро пожаловать в <b>OREOL VPN</b>" in caption
|
||||
assert "<b>Профиль</b>" not in caption
|
||||
assert "<b>Подписка</b>" in caption
|
||||
assert "Статус: <b>Не активна</b>" in caption
|
||||
assert "Срок: <b>—</b>" in caption
|
||||
assert "Трафик: <b>—</b>" in caption
|
||||
|
||||
|
||||
def test_home_panel_keyboard_has_expected_buttons() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_HOME, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "Профиль" not in button_texts
|
||||
assert "💳 Подписка" in button_texts
|
||||
assert "🆘 Поддержка" in button_texts
|
||||
assert "👥 Реферальная система" in button_texts
|
||||
assert "📜 Условия использования" in button_texts
|
||||
assert len(markup.inline_keyboard[0]) == 1
|
||||
assert markup.inline_keyboard[0][0].text == "💳 Подписка"
|
||||
assert markup.inline_keyboard[0][0].callback_data == "payment:menu"
|
||||
|
||||
|
||||
def test_admin_home_panel_keyboard_has_admin_button() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=True,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_HOME, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "🛠 Админ-панель" in button_texts
|
||||
assert len(markup.inline_keyboard[1]) == 1
|
||||
assert markup.inline_keyboard[1][0].text == "🛠 Админ-панель"
|
||||
assert markup.inline_keyboard[1][0].callback_data == "panel:admin"
|
||||
|
||||
|
||||
def test_admin_panel_caption_contains_dashboard_stats() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=True,
|
||||
users=[],
|
||||
admin_total_telegram_users=120,
|
||||
admin_total_cached_users=80,
|
||||
admin_active_cached_users=67,
|
||||
admin_pending_orders=9,
|
||||
admin_review_orders=4,
|
||||
admin_open_tickets=3,
|
||||
admin_pending_referral_bonuses=2,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_ADMIN,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "<b>🛠 Админ-панель OREOL VPN</b>" in caption
|
||||
assert "Пользователей в боте: <b>120</b>" in caption
|
||||
assert "Чеков на проверке: <b>4</b>" in caption
|
||||
assert "Открытых тикетов: <b>3</b>" in caption
|
||||
assert "Бонусов в ожидании: <b>2</b>" in caption
|
||||
|
||||
|
||||
def test_admin_panel_keyboard_has_expected_buttons() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=True,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(
|
||||
section=PANEL_SECTION_ADMIN,
|
||||
context=context,
|
||||
payment_review_url="https://t.me/c/123/56/57",
|
||||
support_ticket_url="https://t.me/c/123/2/3",
|
||||
)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "🔍 Найти пользователя" in button_texts
|
||||
assert "👤 Пользователи" in button_texts
|
||||
assert "🔄 Полная синхронизация" in button_texts
|
||||
assert "💸 Очередь оплат" in button_texts
|
||||
assert "🎫 Тикеты" in button_texts
|
||||
assert "↻ Обновить" in button_texts
|
||||
assert "🏠 Главное меню" in button_texts
|
||||
|
||||
|
||||
def test_subscription_caption_without_subscription_but_with_payment() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
payment_enabled=True,
|
||||
payment_plan_title="OREOL VPN на 30 дней",
|
||||
payment_plan_description="Доступ к VPN на 30 дней",
|
||||
payment_plan_price_stars=250,
|
||||
payment_plan_duration_days=30,
|
||||
payment_plan_traffic_limit_bytes=0,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_SUBSCRIPTION,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "У вас пока нет активного доступа." in caption
|
||||
assert "OREOL VPN на 30 дней" in caption
|
||||
assert "Цена: <b>250 ₽</b>" in caption
|
||||
assert "После выбора тарифа бот покажет реквизиты" in caption
|
||||
|
||||
|
||||
def test_subscription_caption_without_payment_uses_ui_instructions() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
payment_enabled=False,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_SUBSCRIPTION,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "откройте поддержку" in caption
|
||||
assert "short UUID" in caption
|
||||
assert "/link" not in caption
|
||||
|
||||
|
||||
def test_subscription_keyboard_has_buy_button() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
payment_enabled=True,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_SUBSCRIPTION, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "💳 Купить подписку" in button_texts
|
||||
assert "🏠 Главное меню" in button_texts
|
||||
|
||||
|
||||
def test_subscription_keyboard_has_renew_button_when_access_exists() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[_cached_user_view()],
|
||||
payment_enabled=True,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_SUBSCRIPTION, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "💳 Продлить подписку" in button_texts
|
||||
assert "💳 Купить подписку" not in button_texts
|
||||
|
||||
|
||||
def test_subscription_caption_with_existing_access_mentions_renewal() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[_cached_user_view()],
|
||||
payment_enabled=True,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_SUBSCRIPTION,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "Продлить подписку" in caption
|
||||
assert "автоматически добавит выбранный срок" in caption
|
||||
|
||||
|
||||
def test_terms_panel_caption() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_TERMS,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "<b>📜 Правила VPN</b>" in caption
|
||||
assert "использовать VPN только в законных целях" in caption
|
||||
assert "не гарантирует полной анонимности" in caption
|
||||
|
||||
|
||||
def test_support_panel_has_create_ticket_button() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_SUPPORT, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "🎫 Создать тикет" in button_texts
|
||||
assert "🏠 Главное меню" in button_texts
|
||||
|
||||
|
||||
def test_support_panel_has_support_url_button() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(
|
||||
section=PANEL_SECTION_SUPPORT,
|
||||
context=context,
|
||||
support_url="https://t.me/support_account",
|
||||
)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert "Написать в поддержку" in button_texts
|
||||
|
||||
|
||||
def test_support_panel_caption() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_SUPPORT,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "<b>🆘 Помощь и сопровождение</b>" in caption
|
||||
assert "откройте тикет через кнопку ниже" in caption
|
||||
|
||||
|
||||
def test_referral_panel_caption_with_link() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
referral_code="ABCD1234",
|
||||
referral_count=3,
|
||||
referral_link="https://t.me/oreol_vpn_bot?start=ref_ABCD1234",
|
||||
referral_share_url="https://t.me/share/url?url=test",
|
||||
referral_recent_names=["Alex", "Maria"],
|
||||
referral_discount_percent=12,
|
||||
referral_bonus_days=7,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_REFERRAL,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "<b>👥 Реферальная система</b>" in caption
|
||||
assert "Ваш реферальный код: <code>ABCD1234</code>" in caption
|
||||
assert "Приглашено пользователей: <b>3</b>" in caption
|
||||
assert "+7 дней" in caption
|
||||
assert "Чтобы получить скидку 12%" in caption
|
||||
assert "https://t.me/oreol_vpn_bot?start=ref_ABCD1234" in caption
|
||||
assert "Alex" in caption
|
||||
assert "Maria" in caption
|
||||
|
||||
|
||||
def test_referral_caption_uses_runtime_discount_for_applied_code() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
referral_code="ABCD1234",
|
||||
referral_count=1,
|
||||
applied_referral_code="PROMO777",
|
||||
referral_discount_percent=17,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_REFERRAL,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "Код: <code>PROMO777</code>" in caption
|
||||
assert "Скидка перед оплатой: <b>17%</b>" in caption
|
||||
|
||||
|
||||
def test_admin_panel_keyboard_has_settings_button() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=True,
|
||||
users=[],
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_ADMIN, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert any("Настрой" in text for text in button_texts)
|
||||
|
||||
|
||||
def test_home_panel_hides_referral_when_disabled() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
referral_enabled=False,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
markup = build_panel_keyboard(section=PANEL_SECTION_HOME, context=context)
|
||||
button_texts = _button_texts(markup)
|
||||
|
||||
assert all("Реферал" not in text for text in button_texts)
|
||||
|
||||
|
||||
def test_referral_panel_caption_when_disabled() -> None:
|
||||
context = PanelContext(
|
||||
telegram_id=123456789,
|
||||
display_name="Evgeniy Spirin",
|
||||
username="evgeniy",
|
||||
language_code="ru",
|
||||
is_admin=False,
|
||||
users=[],
|
||||
referral_enabled=False,
|
||||
api_error=None,
|
||||
)
|
||||
|
||||
caption = render_panel_caption(
|
||||
section=PANEL_SECTION_REFERRAL,
|
||||
context=context,
|
||||
brand_name="OREOL VPN",
|
||||
)
|
||||
|
||||
assert "отключена" in caption
|
||||
Reference in New Issue
Block a user