feat: перевести навигацию справки на inline-клавиатуру
This commit is contained in:
1 parent
da0da91479
commit
a11b5aac64
7 files changed
+105
-90
No files matched your search
+54
-40
@@ -147,52 +147,28 @@ class HelpRoutingTests(unittest.TestCase):
|
||||
|
||||
|
||||
class HelpNavigationTests(unittest.TestCase):
|
||||
def test_menu_packs_buttons_without_truncating_labels(self):
|
||||
from help_message import HELP_SECTIONS, HELP_SECTION_ORDER, help_menu_html
|
||||
def test_menu_contains_no_embedded_buttons(self):
|
||||
from help_message import help_menu_html
|
||||
|
||||
menu = help_menu_html()
|
||||
rows = menu.split("<tg-button-row")[1:]
|
||||
self.assertLess(len(rows), len(HELP_SECTION_ORDER))
|
||||
for row in rows:
|
||||
self.assertTrue(row.startswith(' align="left">'), row)
|
||||
self.assertLessEqual(row.count("<tg-button "), 2, row)
|
||||
labels = [
|
||||
title
|
||||
for title, _body in HELP_SECTIONS.values()
|
||||
if f">{title}</tg-button>" in row
|
||||
]
|
||||
self.assertLessEqual(
|
||||
sum(len(title) for title in labels) + max(0, len(labels) - 1),
|
||||
24,
|
||||
row,
|
||||
)
|
||||
for section, (title, _body) in HELP_SECTIONS.items():
|
||||
self.assertIn(f'data="help:{section}"', menu)
|
||||
self.assertIn(f">{title}</tg-button>", menu)
|
||||
self.assertNotIn('data="help:menu"', menu)
|
||||
self.assertNotIn("В меню", menu)
|
||||
self.assertNotIn("<tg-button", help_menu_html())
|
||||
|
||||
def test_section_navigates_to_other_sections_without_menu_button(self):
|
||||
def test_section_contains_no_embedded_buttons(self):
|
||||
from help_message import HELP_SECTIONS, help_section_html
|
||||
|
||||
for section in HELP_SECTIONS:
|
||||
html = help_section_html(section)
|
||||
self.assertNotIn('data="help:menu"', html)
|
||||
self.assertNotIn("В меню", html)
|
||||
for other in HELP_SECTIONS:
|
||||
if other == section:
|
||||
continue
|
||||
self.assertIn(f'data="help:{other}"', html, section)
|
||||
with self.subTest(section=section):
|
||||
self.assertNotIn("<tg-button", help_section_html(section))
|
||||
|
||||
def test_current_section_is_disabled(self):
|
||||
from help_message import HELP_SECTIONS, help_section_html
|
||||
def test_help_keyboard_has_one_button_per_section_with_stable_callback_data(self):
|
||||
from help_message import HELP_SECTIONS, HELP_SECTION_ORDER
|
||||
from keyboards import help_inline_keyboard
|
||||
|
||||
html = help_section_html("tone")
|
||||
self.assertIn('<tg-button type="disabled">🎨 Tone of Voice</tg-button>', html)
|
||||
self.assertNotIn('data="help:tone"', html)
|
||||
for section in HELP_SECTIONS:
|
||||
if section != "tone":
|
||||
self.assertIn(f'data="help:{section}" style="primary"', html)
|
||||
rows = help_inline_keyboard().inline_keyboard
|
||||
self.assertEqual(len(rows), len(HELP_SECTION_ORDER))
|
||||
for section, row in zip(HELP_SECTION_ORDER, rows, strict=True):
|
||||
self.assertEqual(len(row), 1)
|
||||
self.assertEqual(row[0].text, HELP_SECTIONS[section][0])
|
||||
self.assertEqual(row[0].callback_data, f"help:{section}")
|
||||
|
||||
def test_unknown_section_falls_back_to_menu(self):
|
||||
from help_message import help_view
|
||||
@@ -249,6 +225,40 @@ class OnboardingTests(unittest.IsolatedAsyncioTestCase):
|
||||
callback.message = message
|
||||
return callback
|
||||
|
||||
async def test_edit_rich_message_attaches_standard_keyboard(self):
|
||||
message_bot = AsyncMock()
|
||||
message = Message(
|
||||
message_id=80,
|
||||
date=datetime.now(),
|
||||
chat=Chat(id=5, type="private"),
|
||||
).as_(message_bot)
|
||||
markup = bot.help_inline_keyboard()
|
||||
|
||||
result = await bot.edit_rich_message(
|
||||
message,
|
||||
bot.help_view("tone"),
|
||||
reply_markup=markup,
|
||||
)
|
||||
|
||||
self.assertTrue(result)
|
||||
message_bot.edit_message_text.assert_awaited_once()
|
||||
call = message_bot.edit_message_text.await_args.kwargs
|
||||
self.assertEqual(call["chat_id"], 5)
|
||||
self.assertEqual(call["message_id"], 80)
|
||||
self.assertEqual(call["reply_markup"], markup)
|
||||
self.assertEqual(call["rich_message"], bot.InputRichMessage(html=bot.help_view("tone")))
|
||||
|
||||
async def test_edit_rich_message_treats_unchanged_content_as_success(self):
|
||||
message_bot = AsyncMock()
|
||||
message_bot.edit_message_text.side_effect = RuntimeError("Bad Request: message is not modified")
|
||||
message = Message(
|
||||
message_id=81,
|
||||
date=datetime.now(),
|
||||
chat=Chat(id=5, type="private"),
|
||||
).as_(message_bot)
|
||||
|
||||
self.assertTrue(await bot.edit_rich_message(message, bot.help_view("tone")))
|
||||
|
||||
async def test_help_callback_edits_rich_message(self):
|
||||
message = Message(
|
||||
message_id=77,
|
||||
@@ -260,7 +270,11 @@ class OnboardingTests(unittest.IsolatedAsyncioTestCase):
|
||||
with patch.object(bot, "edit_rich_message", new=AsyncMock(return_value=True)) as edit:
|
||||
await bot.help_navigation(callback, _StubState("help"))
|
||||
|
||||
edit.assert_awaited_once_with(message, bot.help_view("tone"))
|
||||
edit.assert_awaited_once_with(
|
||||
message,
|
||||
bot.help_view("tone"),
|
||||
reply_markup=bot.help_inline_keyboard(),
|
||||
)
|
||||
callback.answer.assert_awaited_once_with()
|
||||
|
||||
async def test_help_callback_reports_error_when_edit_fails(self):
|
||||
|
||||
Reference in new issue
Block a user