"""Test downloads watchdog functionality.""" import asyncio import tempfile from pathlib import Path import pytest from pytest_httpserver import HTTPServer from browser_use.browser import BrowserSession from browser_use.browser.events import ( BrowserConnectedEvent, BrowserStartEvent, BrowserStopEvent, BrowserStoppedEvent, NavigateToUrlEvent, ) from browser_use.browser.profile import BrowserProfile @pytest.mark.skip(reason='TODO: fix') async def test_downloads_watchdog_lifecycle(): """Test that DownloadsWatchdog starts and stops with browser session.""" # Create temp directory for downloads with tempfile.TemporaryDirectory() as temp_dir: downloads_path = Path(temp_dir) profile = BrowserProfile(headless=True, downloads_path=downloads_path) session = BrowserSession(browser_profile=profile) # Check that downloads watchdog is None initially assert session._downloads_watchdog is None try: # Start browser session.event_bus.dispatch(BrowserStartEvent()) await session.event_bus.expect(BrowserConnectedEvent, timeout=5.0) # Check that downloads watchdog is attached assert session._downloads_watchdog is not None # Verify watchdog has proper session reference assert session._downloads_watchdog.browser_session is session finally: # Clean shutdown try: session.event_bus.dispatch(BrowserStopEvent()) await session.event_bus.expect(BrowserStoppedEvent, timeout=3.0) except Exception: # If graceful shutdown fails, force cleanup await session.kill() # Always stop event bus to prevent hanging await session.event_bus.stop(clear=True, timeout=5) @pytest.mark.skip(reason='TODO: fix') async def test_downloads_watchdog_file_detection(download_test_server): """Test that DownloadsWatchdog detects file downloads.""" # Create temp directory for downloads with tempfile.TemporaryDirectory() as temp_dir: downloads_path = Path(temp_dir) profile = BrowserProfile(headless=True, downloads_path=downloads_path) session = BrowserSession(browser_profile=profile) try: # Start browser session.event_bus.dispatch(BrowserStartEvent()) await session.event_bus.expect(BrowserConnectedEvent, timeout=5.0) # Navigate to test page test_url = download_test_server.url_for('/') await session.event_bus.dispatch(NavigateToUrlEvent(url=test_url)) # Skip complex element selection for now - would need to implement selector-to-index conversion pytest.skip('Complex element selection needs refactoring for CDP events') # Wait for download to complete await asyncio.sleep(2.0) # Verify file was downloaded downloaded_files = list(downloads_path.glob('*')) assert len(downloaded_files) == 1, f'Expected 1 file, got {len(downloaded_files)}: {downloaded_files}' # Verify file content downloaded_file = downloaded_files[0] assert downloaded_file.name == 'test.pdf' assert downloaded_file.read_bytes() == b'PDF content' finally: # Clean shutdown try: session.event_bus.dispatch(BrowserStopEvent()) await session.event_bus.expect(BrowserStoppedEvent, timeout=3.0) except Exception: # If graceful shutdown fails, force cleanup await session.kill() # Always stop event bus to prevent hanging await session.event_bus.stop(clear=True, timeout=5) @pytest.fixture def comprehensive_download_test_server(): """Create a test server with downloadable files.""" httpserver = HTTPServer(host='127.0.0.1', port=0) httpserver.start() # Serve a main page with download links main_page_html = """ Download Test Page

Download Test Page

Download PDF
Download Text """ httpserver.expect_request('/').respond_with_data(main_page_html, content_type='text/html') # PDF handler httpserver.expect_request('/download/test.pdf').respond_with_data( b'PDF content', status=200, headers={'Content-Type': 'application/pdf'} ) # Text handler httpserver.expect_request('/download/test.txt').respond_with_data( b'Text content', status=200, headers={'Content-Type': 'text/plain'} ) yield httpserver httpserver.stop() # @pytest.mark.asyncio # async def test_downloads_watchdog_page_attachment(): # """Test that DownloadsWatchdog attaches to pages properly.""" # # Create temp directory for downloads # with tempfile.TemporaryDirectory() as temp_dir: # downloads_path = Path(temp_dir) # profile = BrowserProfile(headless=True, downloads_path=downloads_path) # session = BrowserSession(browser_profile=profile) # try: # # Start browser # session.event_bus.dispatch(BrowserStartEvent()) # await session.event_bus.expect(BrowserConnectedEvent, timeout=5.0) # # Get downloads watchdog # downloads_watchdog = session._downloads_watchdog # assert downloads_watchdog is not None # # Navigate to create a new page # event = session.event_bus.dispatch(NavigateToUrlEvent(url='data:text/html,

Test Page

')) # await event # await event.event_result(raise_if_any=True, raise_if_none=False) # # Verify watchdog has pages with listeners # assert hasattr(downloads_watchdog, '_pages_with_listeners') # # Give it a moment for page attachment # await asyncio.sleep(0.2) # # The watchdog should have attached to at least one page # # Note: We can't easily verify the internal WeakSet without accessing private attrs # finally: # # Clean shutdown # try: # session.event_bus.dispatch(BrowserStopEvent()) # await session.event_bus.expect(BrowserStoppedEvent, timeout=3.0) # except Exception: # # If graceful shutdown fails, force cleanup # await session.kill() # # Always stop event bus to prevent hanging # await session.event_bus.stop(clear=True, timeout=5) # @pytest.mark.asyncio # async def test_downloads_watchdog_default_downloads_path(): # """Test that DownloadsWatchdog works with default downloads path.""" # # Don't specify downloads path - should use default # profile = BrowserProfile(headless=True) # session = BrowserSession(browser_profile=profile) # try: # # Start browser # session.event_bus.dispatch(BrowserStartEvent()) # await session.event_bus.expect(BrowserConnectedEvent, timeout=5.0) # # Verify downloads watchdog is attached # assert session._downloads_watchdog is not None # # The default downloads path should be set # # Note: We can't easily test the actual download without complex setup # finally: # # Clean shutdown # try: # session.event_bus.dispatch(BrowserStopEvent()) # await session.event_bus.expect(BrowserStoppedEvent, timeout=3.0) # except Exception: # # If graceful shutdown fails, force cleanup # await session.kill() # # Always stop event bus to prevent hanging # await session.event_bus.stop(clear=True, timeout=5) # @pytest.mark.asyncio # async def test_unique_downloads_directories(): # """Test that different browser profiles get unique downloads directories.""" # # Create temp directory for downloads # with tempfile.TemporaryDirectory() as temp_dir: # downloads_path_1 = Path(temp_dir) / 'downloads1' # downloads_path_2 = Path(temp_dir) / 'downloads2' # downloads_path_1.mkdir() # downloads_path_2.mkdir() # profile1 = BrowserProfile(headless=True, downloads_path=downloads_path_1) # profile2 = BrowserProfile(headless=True, downloads_path=downloads_path_2) # session1 = BrowserSession(browser_profile=profile1) # session2 = BrowserSession(browser_profile=profile2) # try: # # Start both browsers # session1.event_bus.dispatch(BrowserStartEvent()) # await session1.event_bus.expect(BrowserConnectedEvent, timeout=5.0) # session2.event_bus.dispatch(BrowserStartEvent()) # await session2.event_bus.expect(BrowserConnectedEvent, timeout=5.0) # # Verify downloads watchdogs are attached # assert session1._downloads_watchdog is not None # assert session2._downloads_watchdog is not None # # Verify they have different downloads paths # assert session1.browser_profile.downloads_path != session2.browser_profile.downloads_path # finally: # # Clean shutdown both sessions # for session in [session1, session2]: # try: # session.event_bus.dispatch(BrowserStopEvent()) # await session.event_bus.expect(BrowserStoppedEvent, timeout=3.0) # except Exception: # # If graceful shutdown fails, force cleanup # await session.kill() # # Always stop event bus to prevent hanging # await session.event_bus.stop(clear=True, timeout=5) # Removed test_downloads_watchdog_actual_download_detection - complex Playwright patterns not suitable for CDP