import pytest from unittest.mock import patch, ANY import asyncio import time from gui_2 import App from events import UserRequestEvent @pytest.mark.timeout(10) @pytest.mark.asyncio async def test_user_request_integration_flow(mock_app: App) -> None: """ Verifies that pushing a UserRequestEvent to the event_queue: 1. Triggers ai_client.send 2. Results in a 'response' event back to the queue 3. Eventually updates the UI state (ai_response, ai_status) after processing GUI tasks. """ app = mock_app # Mock all ai_client methods called during _handle_request_event mock_response = "This is a test AI response" with ( patch('ai_client.send', return_value=mock_response) as mock_send, patch('ai_client.set_custom_system_prompt'), patch('ai_client.set_model_params'), patch('ai_client.set_agent_tools') ): # 1. Create and push a UserRequestEvent event = UserRequestEvent( prompt="Hello AI", stable_md="Context", file_items=[], disc_text="History", base_dir="." ) # 2. Push event to the app's internal loop await app.event_queue.put("user_request", event) # 3. Wait for ai_client.send to be called (polling background thread) start_time = time.time() while not mock_send.called and time.time() - start_time < 5: await asyncio.sleep(0.1) assert mock_send.called, "ai_client.send was not called within timeout" mock_send.assert_called_once_with( "Context", "Hello AI", ".", [], "History", pre_tool_callback=ANY, qa_callback=ANY ) # 4. Wait for the response to propagate to _pending_gui_tasks and update UI # We call _process_pending_gui_tasks manually to simulate a GUI frame update. start_time = time.time() success = False while time.time() - start_time < 3: app._process_pending_gui_tasks() if app.ai_response == mock_response and app.ai_status == "done": success = True break await asyncio.sleep(0.1) assert success, f"UI state was not updated. ai_response: '{app.ai_response}', status: '{app.ai_status}'" assert app.ai_response == mock_response assert app.ai_status == "done" @pytest.mark.timeout(10) @pytest.mark.asyncio async def test_user_request_error_handling(mock_app: App) -> None: """ Verifies that if ai_client.send raises an exception, the UI is updated with the error state. """ app = mock_app with ( patch('ai_client.send', side_effect=Exception("API Failure")), patch('ai_client.set_custom_system_prompt'), patch('ai_client.set_model_params'), patch('ai_client.set_agent_tools') ): event = UserRequestEvent( prompt="Trigger Error", stable_md="", file_items=[], disc_text="", base_dir="." ) await app.event_queue.put("user_request", event) # Poll for error state by processing GUI tasks start_time = time.time() success = False while time.time() - start_time < 5: app._process_pending_gui_tasks() if app.ai_status == "error" and "ERROR: API Failure" in app.ai_response: success = True break await asyncio.sleep(0.1) assert success, f"Error state was not reflected in UI. status: {app.ai_status}, response: {app.ai_response}"