- help_message.py: добавлен WELCOME_RICH_HTML (приветствие, примеры, скриншоты) - bot.py: send_rich_help -> send_rich_html(html, stage) + send_rich_message с plain-fallback - bot.py: start теперь шлёт welcome Rich Message, пауза 0.8с, затем help_command - help_command вызывает общий send_rich_message — правки HELP_RICH_HTML меняют и онбординг - тесты: OnboardingTests (3), README/IDEA/VERSION 0.1.0+22
101 lines
4.2 KiB
Python
101 lines
4.2 KiB
Python
import asyncio
|
|
import unittest
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import bot
|
|
|
|
|
|
class DeployNoticeTests(unittest.IsolatedAsyncioTestCase):
|
|
async def test_sends_once_per_new_version_only_in_development(self):
|
|
fake_bot = AsyncMock()
|
|
with (
|
|
patch.object(bot, "DEPLOY_ENV", "development"),
|
|
patch.object(bot, "VERSION", "0.1.0+5"),
|
|
patch.dict("os.environ", {"DEV_CHAT_ID": "2201809732"}, clear=False),
|
|
patch.object(bot, "get_deploy_notice_version", return_value="0.1.0+4"),
|
|
patch.object(bot, "set_deploy_notice_version"),
|
|
patch.object(bot.asyncio, "to_thread", new=AsyncMock(side_effect=["0.1.0+4", None, "0.1.0+5"])),
|
|
):
|
|
await bot.notify_development_deploy(fake_bot)
|
|
await bot.notify_development_deploy(fake_bot)
|
|
fake_bot.send_message.assert_awaited_once_with(chat_id=2201809732, text="🚀 Бот обновлён\nВерсия: 0.1.0+5")
|
|
|
|
async def test_does_not_send_outside_development(self):
|
|
fake_bot = AsyncMock()
|
|
with patch.object(bot, "DEPLOY_ENV", "production"):
|
|
await bot.notify_development_deploy(fake_bot)
|
|
fake_bot.send_message.assert_not_awaited()
|
|
|
|
async def test_deploy_notice_does_not_block_if_test_api_hangs(self):
|
|
fake_bot = AsyncMock()
|
|
fake_bot.send_message.side_effect = asyncio.TimeoutError
|
|
with (
|
|
patch.object(bot, "DEPLOY_ENV", "development"),
|
|
patch.dict("os.environ", {"DEV_CHAT_ID": "2201809732"}, clear=False),
|
|
patch.object(bot, "get_deploy_notice_version", return_value="old"),
|
|
):
|
|
await bot.notify_development_deploy(fake_bot)
|
|
fake_bot.send_message.assert_awaited_once()
|
|
|
|
|
|
|
|
class HelpRoutingTests(unittest.TestCase):
|
|
def test_commands_are_routed_in_command_handler(self):
|
|
self.assertEqual(bot.HELP_COMMANDS, {"help", "помощь"})
|
|
from pathlib import Path
|
|
source = Path(bot.__file__).read_text(encoding="utf-8")
|
|
self.assertIn("async def handle_command_text", source)
|
|
self.assertIn("if command == \"/help\"", source)
|
|
self.assertIn("elif command == \"/start\"", source)
|
|
self.assertIn("elif command == \"/clear\"", source)
|
|
self.assertIn("elif command == \"/idea\"", source)
|
|
self.assertNotIn("idea_voice", source)
|
|
|
|
def test_help_rich_message_contains_usage_scenarios(self):
|
|
from help_message import HELP_RICH_HTML, rich_to_plain
|
|
|
|
text = rich_to_plain(HELP_RICH_HTML)
|
|
self.assertIn("/clear", text)
|
|
self.assertIn("/idea", text)
|
|
self.assertNotIn("/idea_voice", text)
|
|
for term in ("пост", "голосовое", "скриншот", "реплаем", "/help"):
|
|
self.assertIn(term, text)
|
|
|
|
|
|
class OnboardingTests(unittest.IsolatedAsyncioTestCase):
|
|
async def test_start_sends_welcome_rich_then_help_command(self):
|
|
message = AsyncMock()
|
|
message.from_user.id = 42
|
|
message.message_thread_id = None
|
|
calls: list[str] = []
|
|
|
|
async def fake_rich(_message, html, _stage):
|
|
calls.append(html)
|
|
|
|
with (
|
|
patch.object(bot, "notify_development_deploy", new=AsyncMock()),
|
|
patch.object(bot, "ensure_subscription"),
|
|
patch.object(bot.asyncio, "to_thread", new=AsyncMock()),
|
|
patch.object(bot, "send_rich_message", new=fake_rich),
|
|
):
|
|
await bot.start(message)
|
|
self.assertEqual(calls, [bot.WELCOME_RICH_HTML, bot.HELP_RICH_HTML])
|
|
|
|
async def test_start_help_step_reuses_help_command(self):
|
|
from pathlib import Path
|
|
|
|
source = Path(bot.__file__).read_text(encoding="utf-8")
|
|
start_body = source.split("async def start(message: Message) -> None:")[1].split("\nasync def ")[0]
|
|
self.assertIn("await help_command(message)", start_body)
|
|
|
|
def test_welcome_message_has_examples_and_help_handoff(self):
|
|
from help_message import WELCOME_RICH_HTML, rich_to_plain
|
|
|
|
text = rich_to_plain(WELCOME_RICH_HTML)
|
|
for term in ("Привет", "Напиши пост", "скриншот"):
|
|
self.assertIn(term, text)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|