44import discord
55import pytest
66
7+ import typer_bot .commands .admin_panel .unified_actions as unified_actions
78from tests .admin_panel_helpers import get_button as _get_button
89from tests .admin_panel_helpers import has_button as _has_button
910from typer_bot .commands .admin_panel import (
@@ -74,6 +75,7 @@ async def test_unified_panel_calculate_scores_button_posts_results(
7475 admin_cog ,
7576 mock_interaction_admin ,
7677 sample_games ,
78+ monkeypatch ,
7779 ):
7880 fixture_id = await admin_cog .db .create_fixture (
7981 "111111" , 45 , sample_games , datetime .now (UTC ) + timedelta (days = 1 )
@@ -86,18 +88,10 @@ async def test_unified_panel_calculate_scores_button_posts_results(
8688 ["2-1" , "1-1" , "0-2" ],
8789 False ,
8890 )
89- command_channel = MagicMock (spec = discord .TextChannel )
90- command_channel .id = 999999
91- command_channel .send = AsyncMock ()
92- league_channel = MagicMock (spec = discord .TextChannel )
93- league_channel .id = 123456
94- league_channel .send = AsyncMock ()
95- mock_interaction_admin .channel = command_channel
96- admin_cog .bot .get_channel .return_value = None
97- admin_cog .bot .fetch_channel = AsyncMock (return_value = league_channel )
9891 mock_interaction_admin .message = MagicMock ()
9992 mock_interaction_admin .message .edit = AsyncMock ()
100- admin_cog ._create_backup = AsyncMock ()
93+ post_calculation_result = AsyncMock ()
94+ monkeypatch .setattr (unified_actions , "post_calculation_result" , post_calculation_result )
10195
10296 view = UnifiedAdminPanelView (
10397 admin_cog .db ,
@@ -118,74 +112,24 @@ async def test_unified_panel_calculate_scores_button_posts_results(
118112 admin_cog .get_calculate_cooldown ("111111" , str (mock_interaction_admin .user .id ))
119113 is not None
120114 )
121- league_channel . send .assert_awaited_once ()
122- command_channel . send . assert_not_awaited ()
123- assert (
124- "Week 45 results calculated and posted to the league channel"
125- in mock_interaction_admin . response_sent [ - 1 ][ "content" ]
115+ post_calculation_result .assert_awaited_once ()
116+ assert post_calculation_result . call_args . args [: 3 ] == (
117+ admin_cog . bot ,
118+ admin_cog . db ,
119+ mock_interaction_admin ,
126120 )
127- assert "User One" in league_channel .send .call_args .args [0 ]
128121 assert view .selection .fixture_label == "Week 45 [CLOSED]"
129122 assert _has_button (view , "Calculate Scores" ) is False
130123 assert _has_button (view , "Delete Fixture" ) is False
131124 assert mock_interaction_admin .message .edit .await_count == 1
132125
133- @pytest .mark .asyncio
134- async def test_unified_panel_calculate_scores_button_rejects_unavailable_league_channel (
135- self ,
136- admin_cog ,
137- mock_interaction_admin ,
138- sample_games ,
139- ):
140- fixture_id = await admin_cog .db .create_fixture (
141- "111111" , 46 , sample_games , datetime .now (UTC ) + timedelta (days = 1 )
142- )
143- await admin_cog .db .save_results (fixture_id , ["2-1" , "1-1" , "0-2" ])
144- await admin_cog .db .save_prediction (
145- fixture_id ,
146- "111" ,
147- "User One" ,
148- ["2-1" , "1-1" , "0-2" ],
149- False ,
150- )
151- command_channel = MagicMock (spec = discord .TextChannel )
152- command_channel .send = AsyncMock ()
153- mock_interaction_admin .channel = command_channel
154- admin_cog .bot .get_channel .return_value = None
155- admin_cog .bot .fetch_channel = AsyncMock (
156- side_effect = discord .InvalidData ("unknown channel type" )
157- )
158- mock_interaction_admin .message = MagicMock ()
159- mock_interaction_admin .message .edit = AsyncMock ()
160- admin_cog ._create_backup = AsyncMock ()
161-
162- view = UnifiedAdminPanelView (
163- admin_cog .db ,
164- admin_cog .service ,
165- str (mock_interaction_admin .user .id ),
166- "111111" ,
167- admin_commands = admin_cog ,
168- bot = admin_cog .bot ,
169- )
170- await view .load_fixture_options ()
171- view .fixture_select ._values = [str (fixture_id )]
172- await view .fixture_select .callback (mock_interaction_admin )
173-
174- calculate_button = _get_button (view , "Calculate Scores" )
175- await calculate_button .callback (mock_interaction_admin )
176-
177- command_channel .send .assert_not_awaited ()
178- assert (
179- "configured league channel is unavailable"
180- in mock_interaction_admin .response_sent [- 1 ]["content" ].lower ()
181- )
182-
183126 @pytest .mark .asyncio
184127 async def test_stale_calculate_scores_button_refreshes_when_fixture_already_scored (
185128 self ,
186129 admin_cog ,
187130 mock_interaction_admin ,
188131 sample_games ,
132+ monkeypatch ,
189133 ):
190134 fixture_id = await admin_cog .db .create_fixture (
191135 "111111" , 45 , sample_games , datetime .now (UTC ) + timedelta (days = 1 )
@@ -200,8 +144,8 @@ async def test_stale_calculate_scores_button_refreshes_when_fixture_already_scor
200144 )
201145 mock_interaction_admin .message = MagicMock ()
202146 mock_interaction_admin .message .edit = AsyncMock ()
203- admin_cog . _create_backup = AsyncMock ()
204- admin_cog . _post_calculation_to_channel = AsyncMock ( )
147+ post_calculation_result = AsyncMock ()
148+ monkeypatch . setattr ( unified_actions , "post_calculation_result" , post_calculation_result )
205149 view = UnifiedAdminPanelView (
206150 admin_cog .db ,
207151 admin_cog .service ,
@@ -219,8 +163,7 @@ async def test_stale_calculate_scores_button_refreshes_when_fixture_already_scor
219163 await stale_button .callback (mock_interaction_admin )
220164
221165 assert "no longer open" in mock_interaction_admin .response_sent [- 1 ]["content" ]
222- admin_cog ._create_backup .assert_not_awaited ()
223- admin_cog ._post_calculation_to_channel .assert_not_awaited ()
166+ post_calculation_result .assert_not_awaited ()
224167 assert view .selection .fixture_label == "Week 45 [CLOSED]"
225168 assert _has_button (view , "Calculate Scores" ) is False
226169 assert _has_button (view , "Delete Fixture" ) is False
@@ -232,6 +175,7 @@ async def test_unified_panel_calculate_scores_button_rejects_active_cooldown(
232175 admin_cog ,
233176 mock_interaction_admin ,
234177 sample_games ,
178+ monkeypatch ,
235179 ):
236180 fixture_id = await admin_cog .db .create_fixture (
237181 "111111" , 47 , sample_games , datetime .now (UTC ) + timedelta (days = 1 )
@@ -241,6 +185,8 @@ async def test_unified_panel_calculate_scores_button_rejects_active_cooldown(
241185 "111111" , str (mock_interaction_admin .user .id ), current_time = now ().timestamp ()
242186 )
243187 admin_cog .service .calculate_fixture_scores = AsyncMock ()
188+ post_calculation_result = AsyncMock ()
189+ monkeypatch .setattr (unified_actions , "post_calculation_result" , post_calculation_result )
244190
245191 view = UnifiedAdminPanelView (
246192 admin_cog .db ,
@@ -258,20 +204,22 @@ async def test_unified_panel_calculate_scores_button_rejects_active_cooldown(
258204 await calculate_button .callback (mock_interaction_admin )
259205
260206 assert "Please wait" in mock_interaction_admin .response_sent [- 1 ]["content" ]
207+ post_calculation_result .assert_not_awaited ()
261208
262209 @pytest .mark .asyncio
263210 async def test_unified_panel_calculate_scores_button_handles_service_error (
264211 self ,
265212 admin_cog ,
266213 mock_interaction_admin ,
267214 sample_games ,
215+ monkeypatch ,
268216 ):
269217 fixture_id = await admin_cog .db .create_fixture (
270218 "111111" , 48 , sample_games , datetime .now (UTC ) + timedelta (days = 1 )
271219 )
272220 await admin_cog .db .save_results (fixture_id , ["1-0" , "1-1" , "0-0" ])
273- admin_cog . _create_backup = AsyncMock ()
274-
221+ post_calculation_result = AsyncMock ()
222+ monkeypatch . setattr ( unified_actions , "post_calculation_result" , post_calculation_result )
275223 view = UnifiedAdminPanelView (
276224 admin_cog .db ,
277225 admin_cog .service ,
@@ -291,6 +239,42 @@ async def test_unified_panel_calculate_scores_button_handles_service_error(
291239 mock_interaction_admin .response_sent [- 1 ]["content" ]
292240 == "No predictions found for this fixture"
293241 )
242+ post_calculation_result .assert_not_awaited ()
243+
244+ @pytest .mark .asyncio
245+ async def test_unified_panel_calculate_scores_button_requires_bot_context (
246+ self ,
247+ admin_cog ,
248+ mock_interaction_admin ,
249+ sample_games ,
250+ monkeypatch ,
251+ ):
252+ fixture_id = await admin_cog .db .create_fixture (
253+ "111111" , 49 , sample_games , datetime .now (UTC ) + timedelta (days = 1 )
254+ )
255+ await admin_cog .db .save_results (fixture_id , ["1-0" , "1-1" , "0-0" ])
256+ admin_cog .service .calculate_fixture_scores = AsyncMock ()
257+ post_calculation_result = AsyncMock ()
258+ monkeypatch .setattr (unified_actions , "post_calculation_result" , post_calculation_result )
259+
260+ view = UnifiedAdminPanelView (
261+ admin_cog .db ,
262+ admin_cog .service ,
263+ str (mock_interaction_admin .user .id ),
264+ "111111" ,
265+ admin_commands = admin_cog ,
266+ bot = None ,
267+ )
268+ await view .load_fixture_options ()
269+ view .fixture_select ._values = [str (fixture_id )]
270+ await view .fixture_select .callback (mock_interaction_admin )
271+
272+ calculate_button = _get_button (view , "Calculate Scores" )
273+ await calculate_button .callback (mock_interaction_admin )
274+
275+ assert "unavailable" in mock_interaction_admin .response_sent [- 1 ]["content" ]
276+ admin_cog .service .calculate_fixture_scores .assert_not_awaited ()
277+ post_calculation_result .assert_not_awaited ()
294278
295279 @pytest .mark .asyncio
296280 async def test_unified_panel_post_results_button_opens_confirmation (
0 commit comments