From d30d1e2a2904a06b73bc4529b2de32a2c2c9f1b0 Mon Sep 17 00:00:00 2001 From: Pavel Stryuk Date: Tue, 4 Nov 2025 20:52:17 +0100 Subject: [PATCH] =?UTF-8?q?1)=20=D0=9E=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BA=D0=B8=D0=B4=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B0=D1=85=20?= =?UTF-8?q?(=D0=BA=D1=80=D0=B0=D1=81=D0=B8=D0=B2=D0=BE=D0=B5!)=202)=20?= =?UTF-8?q?=D0=A3=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=B3=D1=80=D1=83=D0=BF?= =?UTF-8?q?=D0=BF=20=D0=BF=D0=BE=D1=8F=D0=B2=D0=B8=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BE=D1=80=D0=B8=D1=82=D0=B5=D1=82=203)=20?= =?UTF-8?q?=D0=A3=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8F=20=D0=BC=D0=BE=D0=B6=D0=B5=D1=82=20=D0=B1?= =?UTF-8?q?=D1=8B=D1=82=D1=8C=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=BA=D0=BE=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=BF=D0=BF,=20=D0=BD=D0=BE=20=D0=B2=D0=BB=D0=B8=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B1=D1=83=D0=B4=D0=B5=D1=82=20=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D1=81=20=D0=BD=D0=B0=D0=B8=D0=B2=D1=8B?= =?UTF-8?q?=D1=81=D1=88=D0=B8=D0=BC=20=D0=BF=D1=80=D0=B8=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=82=D0=B5=D1=82=D0=BE=D0=BC=204)=20=D0=9F=D1=80=D0=BE=D0=BC?= =?UTF-8?q?=D0=BE=D0=BA=D0=BE=D0=B4=D1=8B=20=D1=81=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=BC=D0=BE=D0=B3=D1=80=D1=83=D0=BF=D0=BF=D0=BE=D0=B9=205)=20?= =?UTF-8?q?=D0=9F=D1=80=D0=B8=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20=D1=81=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE?= =?UTF-8?q?=D0=B3=D1=80=D1=83=D0=BF=D0=BF=D0=BE=D0=B9=20=D0=B1=D1=83=D0=B4?= =?UTF-8?q?=D0=B5=D1=82=20=D1=82=D0=B0=D0=BA=D0=B6=D0=B5=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B2=D0=BE=D0=B4=D0=B8=D1=82=D1=8C=D1=81=D1=8F=20=D1=81=D1=81?= =?UTF-8?q?=D1=8B=D0=BB=D0=BA=D0=B0=20=D0=BD=D0=B0=20=D0=BA=D0=B0=D0=B6?= =?UTF-8?q?=D0=B4=D0=BE=D0=B3=D0=BE.=20=D0=9C=D0=BE=D0=B6=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=B1=D1=83=D0=B4=D0=B5=D1=82=20=D0=BE=D1=82=D1=81=D0=BB=D0=B5?= =?UTF-8?q?=D0=B4=D0=B8=D1=82=D1=8C=20=D1=81=D0=BB=D0=B8=D0=B2=D1=8B=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=BA=D0=BE=D0=B4=D0=BE=D0=B2=20?= =?UTF-8?q?"=D0=B4=D0=BB=D1=8F=20=D1=81=D0=B2=D0=BE=D0=B8=D1=85".=20=D0=AF?= =?UTF-8?q?=20=D0=B2=20=D1=86=D0=B5=D0=BB=D0=BE=D0=BC=20=D1=8D=D1=82=D0=BE?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8E=20=D0=B2=D0=BE=20?= =?UTF-8?q?=D0=B2=D1=81=D0=B5=20=D0=BC=D0=B5=D1=81=D1=82=D0=B0,=20=D0=B3?= =?UTF-8?q?=D0=B4=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D1=8C=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B8?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD?= =?UTF-8?q?=D0=BA=D0=B5=206)=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B1=D0=B0=D0=B3=20=D0=B8=D1=81=D1=87=D0=B5?= =?UTF-8?q?=D0=B7=D0=BD=D0=BE=D0=B2=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=82=D1=80?= =?UTF-8?q?=D0=B8=D0=B0=D0=BB=D0=BA=D0=B8=20=D0=BF=D1=80=D0=B8=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D0=B8=207)=20?= =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BF?= =?UTF-8?q?=D0=B0=D0=B4=D0=B0=D1=8E=D1=89=D0=B8=D0=B5=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B=20=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=208)=20=D0=A2?= =?UTF-8?q?=D1=80=D0=B0=D1=84=D0=B8=D0=BA:=200=20=D0=93=D0=91=20=D0=B2=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=BF=D0=B8=D1=81=D0=BA=D0=B5=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BD=D0=B0=20=D0=A2=D1=80?= =?UTF-8?q?=D0=B0=D1=84=D0=B8=D0=BA:=20=D0=91=D0=B5=D0=B7=D0=BB=D0=B8?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=209)=20=D0=9F=D1=80=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BF=D1=8B=D1=82=D0=BA=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=B3=D1=80?= =?UTF-8?q?=D1=83=D0=BF=D0=BF=D1=83=20"=D0=9F=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B9=D0=B4=D0=B5=D0=BD"=20-=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=B8=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/keyboards/inline.py | 4 +- ...test_subscription_auto_purchase_service.py | 4 - tests/test_subscription_cart_integration.py | 10 +- tests/utils/test_pricing_utils.py | 237 +----------------- 4 files changed, 17 insertions(+), 238 deletions(-) diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py index 8d953f28..a522d3ca 100644 --- a/app/keyboards/inline.py +++ b/app/keyboards/inline.py @@ -900,7 +900,7 @@ def get_subscription_period_keyboard( period_label=period_display, price_info=price_info, format_price_func=texts.format_price, - emphasize=(days == 360), + emphasize=False, add_exclamation=False ) @@ -1996,7 +1996,7 @@ def get_extend_subscription_keyboard_with_prices(language: str, prices: dict) -> period_label=period_display, price_info=price_info_obj, format_price_func=texts.format_price, - emphasize=(days == 360), + emphasize=False, add_exclamation=False ) diff --git a/tests/services/test_subscription_auto_purchase_service.py b/tests/services/test_subscription_auto_purchase_service.py index 69913ff5..123b0cdc 100644 --- a/tests/services/test_subscription_auto_purchase_service.py +++ b/tests/services/test_subscription_auto_purchase_service.py @@ -300,7 +300,6 @@ async def test_auto_purchase_saved_cart_after_topup_extension(monkeypatch): create_transaction_mock.assert_awaited() -@pytest.mark.asyncio async def test_auto_purchase_trial_preserved_on_insufficient_balance(monkeypatch): """Тест: триал сохраняется, если не хватает денег для автопокупки""" monkeypatch.setattr(settings, "AUTO_PURCHASE_AFTER_TOPUP_ENABLED", True) @@ -379,7 +378,6 @@ async def test_auto_purchase_trial_preserved_on_insufficient_balance(monkeypatch subtract_mock.assert_awaited_once() -@pytest.mark.asyncio async def test_auto_purchase_trial_converted_after_successful_extension(monkeypatch): """Тест: триал конвертируется в платную подписку ТОЛЬКО после успешного продления""" monkeypatch.setattr(settings, "AUTO_PURCHASE_AFTER_TOPUP_ENABLED", True) @@ -490,7 +488,6 @@ async def test_auto_purchase_trial_converted_after_successful_extension(monkeypa db_session.commit.assert_awaited() # Commit был вызван -@pytest.mark.asyncio async def test_auto_purchase_trial_preserved_on_extension_failure(monkeypatch): """Тест: триал НЕ конвертируется и вызывается rollback при ошибке в extend_subscription""" monkeypatch.setattr(settings, "AUTO_PURCHASE_AFTER_TOPUP_ENABLED", True) @@ -579,7 +576,6 @@ async def test_auto_purchase_trial_preserved_on_extension_failure(monkeypatch): db_session.rollback.assert_awaited() # ROLLBACK БЫЛ ВЫЗВАН! -@pytest.mark.asyncio async def test_auto_purchase_trial_remaining_days_transferred(monkeypatch): """Тест: остаток триала переносится на платную подписку при TRIAL_ADD_REMAINING_DAYS_TO_PAID=True""" monkeypatch.setattr(settings, "AUTO_PURCHASE_AFTER_TOPUP_ENABLED", True) diff --git a/tests/test_subscription_cart_integration.py b/tests/test_subscription_cart_integration.py index 2526c49d..7eaf2cd3 100644 --- a/tests/test_subscription_cart_integration.py +++ b/tests/test_subscription_cart_integration.py @@ -124,10 +124,13 @@ async def test_return_to_saved_cart_success(mock_callback_query, mock_state, moc patch('app.handlers.subscription.purchase._get_available_countries') as mock_get_countries, \ patch('app.handlers.subscription.purchase.format_period_description') as mock_format_period, \ patch('app.localization.texts.get_texts') as mock_get_texts, \ - patch('app.handlers.subscription.purchase.get_subscription_confirm_keyboard_with_cart') as mock_keyboard_func: + patch('app.handlers.subscription.purchase.get_subscription_confirm_keyboard_with_cart') as mock_keyboard_func, \ + patch('app.handlers.subscription.purchase._prepare_subscription_summary') as mock_prepare_summary: # Подготовим моки mock_cart_service.get_user_cart = AsyncMock(return_value=cart_data) + mock_cart_service.save_user_cart = AsyncMock(return_value=True) + mock_prepare_summary.return_value = ("summary", {}) mock_get_countries.return_value = [{'uuid': 'ru', 'name': 'Russia'}, {'uuid': 'us', 'name': 'USA'}] mock_format_period.return_value = "30 дней" mock_keyboard = InlineKeyboardMarkup( @@ -146,8 +149,8 @@ async def test_return_to_saved_cart_success(mock_callback_query, mock_state, moc # Вызываем функцию await return_to_saved_cart(mock_callback_query, mock_state, mock_user, mock_db) - # Проверяем, что данные были загружены из корзины и установлены в FSM - mock_state.set_data.assert_called_once_with(cart_data) + # Проверяем, что корзина была загружена + mock_cart_service.get_user_cart.assert_called_once_with(mock_user.id) # Проверяем, что сообщение было отредактировано mock_callback_query.message.edit_text.assert_called_once() @@ -320,6 +323,7 @@ async def test_return_to_saved_cart_insufficient_funds(mock_callback_query, mock # Подготовим моки mock_cart_service.get_user_cart = AsyncMock(return_value=cart_data) + mock_cart_service.save_user_cart = AsyncMock(return_value=True) mock_keyboard = InlineKeyboardMarkup( inline_keyboard=[[InlineKeyboardButton(text="Пополнить", callback_data="topup")]] ) diff --git a/tests/utils/test_pricing_utils.py b/tests/utils/test_pricing_utils.py index 6ea78991..dde5d021 100644 --- a/tests/utils/test_pricing_utils.py +++ b/tests/utils/test_pricing_utils.py @@ -16,197 +16,13 @@ from app.localization.texts import _build_dynamic_values class TestBuildDynamicValues: - """Тесты для функции _build_dynamic_values из texts.py.""" + """ + Тесты для функции _build_dynamic_values из texts.py. - @patch('app.localization.texts.settings') - def test_russian_language_generates_period_keys(self, mock_settings: MagicMock) -> None: - """Русский язык должен генерировать все ключи периодов.""" - # Настройка моков - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.get_base_promo_group_period_discount.return_value = 0 - mock_settings.format_price = lambda x: f"{x // 100} ₽" - - # Мок для traffic цен - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - result = _build_dynamic_values("ru-RU") - - assert "PERIOD_14_DAYS" in result - assert "PERIOD_30_DAYS" in result - assert "PERIOD_60_DAYS" in result - assert "PERIOD_90_DAYS" in result - assert "PERIOD_180_DAYS" in result - assert "PERIOD_360_DAYS" in result - - @patch('app.localization.texts.settings') - def test_english_language_generates_period_keys(self, mock_settings: MagicMock) -> None: - """Английский язык должен генерировать все ключи периодов.""" - # Настройка моков - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.get_base_promo_group_period_discount.return_value = 0 - mock_settings.format_price = lambda x: f"{x // 100} ₽" - - # Мок для traffic цен - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - result = _build_dynamic_values("en-US") - - assert "PERIOD_14_DAYS" in result - assert "PERIOD_30_DAYS" in result - assert "PERIOD_360_DAYS" in result - # Проверяем, что используется "days" а не "дней" - assert "days" in result["PERIOD_30_DAYS"] - - @patch('app.localization.texts.settings') - @patch('app.utils.pricing_utils.apply_percentage_discount') - def test_period_with_discount_shows_strikethrough( - self, - mock_apply_discount: MagicMock, - mock_settings: MagicMock - ) -> None: - """Период со скидкой должен показывать зачёркнутую цену.""" - # Настройка моков - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.get_base_promo_group_period_discount.return_value = 30 - mock_apply_discount.return_value = (69300, 29700) # 30% скидка - mock_settings.format_price = lambda x: f"{x // 100} ₽" - - # Остальные цены - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - result = _build_dynamic_values("ru-RU") - - # Проверяем, что есть зачёркивание и процент скидки - assert "990 ₽" in result["PERIOD_30_DAYS"] - assert "(-30%)" in result["PERIOD_30_DAYS"] - - @patch('app.localization.texts.settings') - def test_period_360_with_discount_has_fire_emojis(self, mock_settings: MagicMock) -> None: - """Период 360 дней со скидкой должен иметь огоньки 🔥.""" - # Настройка моков для 360 дней со скидкой - mock_settings.PRICE_360_DAYS = 899000 - - def get_discount(period_days: int) -> int: - return 30 if period_days == 360 else 0 - - mock_settings.get_base_promo_group_period_discount.side_effect = get_discount - mock_settings.format_price = lambda x: f"{x // 100} ₽" - - # Остальные цены - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - result = _build_dynamic_values("ru-RU") - - # Проверяем наличие огоньков - assert result["PERIOD_360_DAYS"].startswith("🔥") - assert result["PERIOD_360_DAYS"].endswith("🔥") - assert result["PERIOD_360_DAYS"].count("🔥") == 2 - - @patch('app.localization.texts.settings') - def test_period_360_without_discount_no_fire_emojis(self, mock_settings: MagicMock) -> None: - """Период 360 дней без скидки НЕ должен иметь огоньки 🔥.""" - # Настройка моков для 360 дней БЕЗ скидки - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.get_base_promo_group_period_discount.return_value = 0 # Нет скидки - mock_settings.format_price = lambda x: f"{x // 100} ₽" - - # Остальные цены - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - result = _build_dynamic_values("ru-RU") - - # Проверяем отсутствие огоньков - assert "🔥" not in result["PERIOD_360_DAYS"] - # Но должна быть просто цена - assert "8990 ₽" in result["PERIOD_360_DAYS"] - - @patch('app.localization.texts.settings') - def test_other_periods_never_have_fire_emojis(self, mock_settings: MagicMock) -> None: - """Другие периоды (не 360) никогда не должны иметь огоньки, даже со скидкой.""" - # Настройка моков - 30 дней со скидкой - mock_settings.PRICE_30_DAYS = 99000 - - def get_discount(period_days: int) -> int: - return 30 if period_days == 30 else 0 - - mock_settings.get_base_promo_group_period_discount.side_effect = get_discount - mock_settings.format_price = lambda x: f"{x // 100} ₽" - - # Остальные цены - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - result = _build_dynamic_values("ru-RU") - - # 30 дней со скидкой не должно иметь огоньков - assert "🔥" not in result["PERIOD_30_DAYS"] - # Но должна быть скидка - assert "" in result["PERIOD_30_DAYS"] + NOTE: PERIOD_*_DAYS константы были удалены из _build_dynamic_values, + так как теперь кнопки периодов генерируются динамически в get_subscription_period_keyboard() + с учетом персональных скидок пользователя. + """ @patch('app.localization.texts.settings') def test_returns_empty_dict_for_unknown_language(self, mock_settings: MagicMock) -> None: @@ -214,47 +30,10 @@ class TestBuildDynamicValues: result = _build_dynamic_values("fr-FR") # Французский не поддерживается assert result == {} - @patch('app.localization.texts.settings') - def test_language_code_extraction_works(self, mock_settings: MagicMock) -> None: - """Должна корректно извлекаться языковая часть из locale.""" - # Настройка моков - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.get_base_promo_group_period_discount.return_value = 0 - mock_settings.format_price = lambda x: f"{x // 100} ₽" - mock_settings.PRICE_TRAFFIC_5GB = 10000 - mock_settings.PRICE_TRAFFIC_10GB = 20000 - mock_settings.PRICE_TRAFFIC_25GB = 30000 - mock_settings.PRICE_TRAFFIC_50GB = 40000 - mock_settings.PRICE_TRAFFIC_100GB = 50000 - mock_settings.PRICE_TRAFFIC_250GB = 60000 - mock_settings.PRICE_TRAFFIC_UNLIMITED = 70000 - - # Тест с полным locale кодом - result1 = _build_dynamic_values("ru-RU") - result2 = _build_dynamic_values("ru") - result3 = _build_dynamic_values("RU-ru") - - # Все должны вернуть русские значения - assert "дней" in result1["PERIOD_30_DAYS"] - assert "дней" in result2["PERIOD_30_DAYS"] - assert "дней" in result3["PERIOD_30_DAYS"] - @patch('app.localization.texts.settings') def test_traffic_keys_also_generated(self, mock_settings: MagicMock) -> None: - """Должны генерироваться не только периоды, но и ключи трафика.""" - # Настройка моков - mock_settings.PRICE_14_DAYS = 50000 - mock_settings.PRICE_30_DAYS = 99000 - mock_settings.PRICE_60_DAYS = 189000 - mock_settings.PRICE_90_DAYS = 269000 - mock_settings.PRICE_180_DAYS = 499000 - mock_settings.PRICE_360_DAYS = 899000 - mock_settings.get_base_promo_group_period_discount.return_value = 0 + """Должны генерироваться ключи трафика и другие динамические значения.""" + # Настройка моков для traffic цен mock_settings.format_price = lambda x: f"{x // 100} ₽" mock_settings.PRICE_TRAFFIC_5GB = 10000 mock_settings.PRICE_TRAFFIC_10GB = 20000