from __future__ import annotations from types import SimpleNamespace from unittest.mock import AsyncMock import pytest from pyrogram.types import ReplyKeyboardMarkup, ReplyKeyboardRemove async def test_enabling_checkin_button_sends_hideable_keyboard( app_modules, monkeypatch ): points = app_modules.load("wbb.utils.dbpoints") settings = app_modules.load("wbb.services.point_settings") await points.set_point_rules( -100, {"enabled": True, "checkin_enabled": True} ) send_message = AsyncMock(return_value=SimpleNamespace(id=1)) monkeypatch.setattr(settings.app, "send_message", send_message) rules = await settings.apply_point_rules( -100, {"checkin_button_enabled": True} ) assert rules["checkin_button_enabled"] is True assert send_message.await_count == 2 remove_call, keyboard_call = send_message.await_args_list assert isinstance(remove_call.kwargs["reply_markup"], ReplyKeyboardRemove) chat_id, text = keyboard_call.args reply_markup = keyboard_call.kwargs["reply_markup"] assert chat_id == -100 assert "签到快捷按钮已开启" in text assert isinstance(reply_markup, ReplyKeyboardMarkup) assert reply_markup.is_persistent is False assert reply_markup.resize_keyboard is True assert reply_markup.one_time_keyboard is True assert reply_markup.keyboard[0][0].text == "签到" stored = await points.rulesdb.find_one({"chat_id": -100}) assert stored["checkin_keyboard_version"] == settings.CHECKIN_KEYBOARD_VERSION async def test_checkin_button_sync_is_idempotent_and_follows_points_state( app_modules, monkeypatch ): points = app_modules.load("wbb.utils.dbpoints") settings = app_modules.load("wbb.services.point_settings") await points.set_point_rules( -100, { "enabled": True, "checkin_enabled": True, "checkin_button_enabled": True, }, ) send_message = AsyncMock(return_value=SimpleNamespace(id=1)) monkeypatch.setattr(settings.app, "send_message", send_message) await settings.apply_point_rules(-100, {"checkin_button_enabled": True}) send_message.assert_not_awaited() rules = await settings.apply_point_rules(-100, {"enabled": False}) assert rules["checkin_button_enabled"] is True reply_markup = send_message.await_args.kwargs["reply_markup"] assert isinstance(reply_markup, ReplyKeyboardRemove) async def test_checkin_button_send_failure_rolls_back_rule(app_modules, monkeypatch): points = app_modules.load("wbb.utils.dbpoints") settings = app_modules.load("wbb.services.point_settings") await points.set_point_rules( -100, {"enabled": True, "checkin_enabled": True} ) monkeypatch.setattr( settings.app, "send_message", AsyncMock(side_effect=RuntimeError("telegram unavailable")), ) with pytest.raises(points.PointsError, match="无法更新群底部签到按钮"): await settings.apply_point_rules( -100, {"checkin_button_enabled": True} ) rules = await points.get_point_rules(-100) assert rules["checkin_button_enabled"] is False async def test_active_checkin_keyboards_are_migrated_only_once( app_modules, monkeypatch ): points = app_modules.load("wbb.utils.dbpoints") settings = app_modules.load("wbb.services.point_settings") await points.set_point_rules( -100, { "enabled": True, "checkin_enabled": True, "checkin_button_enabled": True, }, ) send_message = AsyncMock( side_effect=[ SimpleNamespace(id=1), SimpleNamespace(id=2), ] ) monkeypatch.setattr(settings.app, "send_message", send_message) refreshed = await settings.refresh_active_checkin_keyboards() assert refreshed == 1 assert send_message.await_count == 2 assert isinstance( send_message.await_args_list[0].kwargs["reply_markup"], ReplyKeyboardRemove, ) assert isinstance( send_message.await_args_list[1].kwargs["reply_markup"], ReplyKeyboardMarkup, ) stored = await points.rulesdb.find_one({"chat_id": -100}) assert stored["checkin_keyboard_version"] == settings.CHECKIN_KEYBOARD_VERSION send_message.reset_mock() assert await settings.refresh_active_checkin_keyboards() == 0 send_message.assert_not_awaited()