@@ -1208,19 +1208,33 @@ def test_ctrl_d_at_prompt(say_app, monkeypatch) -> None:
12081208 reason = "Don't have a real Windows console with how we are currently running tests in GitHub Actions" ,
12091209)
12101210@pytest .mark .parametrize (
1211- ('msg' , 'prompt' , 'is_stale' ),
1211+ ('msg' , 'prompt' , 'is_stale' , 'at_continuation_prompt' ),
12121212 [
1213- ("msg_text" , None , False ),
1214- (None , "new_prompt> " , False ),
1215- ("msg_text" , "new_prompt> " , True ),
1213+ ("msg_text" , None , False , False ),
1214+ ("msg_text" , "new_prompt> " , False , False ),
1215+ ("msg_text" , "new_prompt> " , False , True ),
1216+ ("msg_text" , "new_prompt> " , True , False ),
1217+ ("msg_text" , "new_prompt> " , True , True ),
1218+ (None , "new_prompt> " , False , False ),
1219+ (None , "new_prompt> " , False , True ),
1220+ (None , "new_prompt> " , True , False ),
1221+ (None , "new_prompt> " , True , True ),
12161222 # Blank prompt is acceptable
1217- ("msg_text" , "" , False ),
1223+ ("msg_text" , "" , False , False ),
1224+ (None , "" , False , False ),
12181225 ],
12191226)
1220- def test_async_alert (base_app , msg , prompt , is_stale ) -> None :
1227+ def test_async_alert (base_app , msg , prompt , is_stale , at_continuation_prompt ) -> None :
12211228 import time
12221229
1223- with mock .patch ('cmd2.cmd2.print_formatted_text' ) as mock_print :
1230+ with (
1231+ mock .patch ('cmd2.cmd2.print_formatted_text' ) as mock_print ,
1232+ mock .patch ('cmd2.cmd2.get_app' ) as mock_get_app ,
1233+ ):
1234+ # Set up the chained mock: get_app() returns mock_app, which has invalidate()
1235+ mock_app = mock .MagicMock ()
1236+ mock_get_app .return_value = mock_app
1237+
12241238 base_app .add_alert (msg = msg , prompt = prompt )
12251239 alert = base_app ._alert_queue [0 ]
12261240
@@ -1232,6 +1246,8 @@ def test_async_alert(base_app, msg, prompt, is_stale) -> None:
12321246 # In the future
12331247 alert .timestamp = time .monotonic () + 99999999
12341248
1249+ base_app ._at_continuation_prompt = at_continuation_prompt
1250+
12351251 with create_pipe_input () as pipe_input :
12361252 base_app .session = PromptSession (
12371253 input = pipe_input ,
@@ -1243,8 +1259,19 @@ def test_async_alert(base_app, msg, prompt, is_stale) -> None:
12431259
12441260 base_app ._cmdloop ()
12451261
1262+ # If there was a message, patch_stdout handles the redraw (no invalidate)
12461263 if msg :
12471264 assert msg in str (mock_print .call_args_list [0 ])
1265+ mock_app .invalidate .assert_not_called ()
1266+
1267+ # If there's only a prompt update, we expect invalidate() only if not continuation/stale
1268+ elif prompt is not None :
1269+ if is_stale or at_continuation_prompt :
1270+ mock_app .invalidate .assert_not_called ()
1271+ else :
1272+ mock_app .invalidate .assert_called_once ()
1273+
1274+ # The state of base_app.prompt should always be correct regardless of redraw
12481275 if prompt is not None :
12491276 if is_stale :
12501277 assert base_app .prompt != prompt
0 commit comments