diff --git a/test/conftest.py b/test/conftest.py index 213dc5b..8e96e46 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -56,6 +56,25 @@ if sys.platform == "win32": from utils import misc as _misc _win_input.user32 = _NoRealInputUser32(_win_input.user32) + # Tests must not post to the real Discord either. Config reads the webhook + # from the repo's .env, and bot paths under test call + # _save_error_screenshot -> messenger.send_error: on 2026-09-15 a town-manager + # test sent a real "maintenance failed - Buy consumables failed (vendor not + # found)" alert while the live bot was fine. + from config import Config as _Config + from messages import discord_embeds as _discord_embeds, generic_api as _generic_api + + _Config().general["custom_message_hook"] = "" + _Config().general["custom_loot_message_hook"] = "" + _Config().general["message_api_type"] = "" + + class _NoWebhook: + @staticmethod + def from_url(*args, **kwargs): + raise RuntimeError("Discord disabled under pytest") + + _discord_embeds.SyncWebhook = _NoWebhook + _generic_api.requests = type("_NoRequests", (), {"post": staticmethod(lambda *a, **k: None)})() # Window moves / focus steals: tests must not reposition or front D2R either. for _name in ("SetWindowPos", "SetForegroundWindow", "ShowWindow"): setattr(_misc, _name, lambda *args, **kwargs: None) diff --git a/test/test_no_real_side_effects.py b/test/test_no_real_side_effects.py new file mode 100644 index 0000000..c13a525 --- /dev/null +++ b/test/test_no_real_side_effects.py @@ -0,0 +1,21 @@ +"""The suite must not reach the real desktop or the real Discord (see conftest.py).""" +import pytest + + +def test_messenger_is_disabled_under_pytest(): + from messages import Messenger + + assert not Messenger().enabled, "tests would post to the real Discord webhook from .env" + + +def test_discord_webhook_cannot_be_created_under_pytest(): + from messages import discord_embeds + + with pytest.raises(RuntimeError): + discord_embeds.SyncWebhook.from_url("https://discord.com/api/webhooks/1/x") + + +def test_real_input_is_blocked_under_pytest(): + from input_layer import win_input + + assert type(win_input.user32).__name__ == "_NoRealInputUser32"