import pytest from unittest.mock import AsyncMock, patch from src.browser.manager import CamoufoxManager @pytest.mark.asyncio async def test_manager_integration_ghost_cursor(): """ Verify that CamoufoxManager.navigate calls GhostCursor methods. """ # Mock GhostCursorEngine within the manager module context if possible, # or better, mock it via patch on the class instance after init if easier, # but since it's instantiated in __init__, we patch the class in the module. with patch('src.browser.manager.GhostCursorEngine') as MockGhostEngine, \ patch('src.browser.manager.async_playwright') as MockPlaywright: # Setup Mocks mock_engine_instance = MockGhostEngine.return_value mock_engine_instance.move_to = AsyncMock() mock_engine_instance.random_micro_movement = AsyncMock() mock_pw_context = AsyncMock() MockPlaywright.return_value.start.return_value = mock_pw_context # Mock browser, context, page chain... # CamoufoxManager.initialize is complex to mock fully without heavy boilerplate. # We can try to rely on the fact that navigate checks self.page. # Let's instantiate manager manager = CamoufoxManager() # Manually set the mock page to bypass initialize() complexity if we just want to test navigate logic mock_page = AsyncMock() manager.page = mock_page # We also need to inject our mock engine instance if the init already ran? # Yes, line `self.ghost_cursor = GhostCursorEngine()` ran during init. # So manager.ghost_cursor is the mock_engine_instance provided by patch. # EXECUTE await manager.navigate("http://example.com") # VERIFY # 1. Page goto called mock_page.goto.assert_awaited_once_with("http://example.com", wait_until='domcontentloaded') # 2. GhostCursor move_to called assert mock_engine_instance.move_to.called args = mock_engine_instance.move_to.call_args[0] # args: (page, x, y) assert args[0] == mock_page assert 100 <= args[1] <= 1800 # x check assert 100 <= args[2] <= 900 # y check # 3. Random micro movement called mock_engine_instance.random_micro_movement.assert_awaited_once_with(mock_page)