#!/usr/bin/env python3 """ End-to-end Playwright tests for watchlist integration Tests: /watchlist page functionality - filters, settings, scheduler, refresh """ import asyncio import json from pathlib import Path from playwright.async_api import async_playwright BASE_URL = "http://localhost:3000" EVIDENCE_DIR = Path(".sisyphus/evidence") EVIDENCE_DIR.mkdir(parents=True, exist_ok=True) async def main(): # First get auth token import httpx resp = httpx.post( f"{BASE_URL}/api/auth/login", json={"username": "e2etest", "password": "password123"}, ) token_data = resp.json() token = token_data.get("access_token") user = token_data.get("user", {}) print(f"Got token for user: {user.get('username')}") async with async_playwright() as p: browser = await p.chromium.launch( args=["--no-sandbox", "--disable-setuid-sandbox"] ) context = await browser.new_context(viewport={"width": 1920, "height": 1080}) page = await context.new_page() # Set auth BEFORE navigation await page.add_init_script(f""" window.localStorage.setItem('auth_token', '{token}'); window.localStorage.setItem('user', '{json.dumps(user)}'); """) results = [] # Test 1: Navigate to /watchlist print("\n=== Test 1: Navigate to /watchlist ===") await page.goto(f"{BASE_URL}/watchlist") await page.wait_for_load_state("networkidle") await page.wait_for_timeout(2000) await page.screenshot( path=str(EVIDENCE_DIR / "01_watchlist_page.png"), full_page=True ) title = await page.title() url = page.url page_loaded = "Watchlist" in title and "login" not in url.lower() results.append(("Navigate to /watchlist", page_loaded)) print(f"Page title: {title}, URL: {url}") # Test 2: Verify watchlist tab is active (highlighted) print("\n=== Test 2: Verify watchlist tab highlighted ===") active_tab = await page.query_selector( 'button.tab.active:has-text("Watchlist")' ) is_active = active_tab is not None await page.screenshot( path=str(EVIDENCE_DIR / "02_tab_highlighted.png"), full_page=True ) results.append(("Watchlist tab highlighted", is_active)) # Test 3: Verify header/nav matches other tabs print("\n=== Test 3: Verify header/nav ===") header = await page.query_selector("h1") tabs = await page.query_selector_all(".tabs .tab") has_header = header is not None has_tabs = len(tabs) >= 4 await page.screenshot( path=str(EVIDENCE_DIR / "03_header_nav.png"), full_page=True ) results.append(("Header/nav present", has_header and has_tabs)) print(f"Found {len(tabs)} tabs, header: {has_header}") # Test 4: Verify scheduler panel displays correctly print("\n=== Test 4: Verify scheduler panel ===") scheduler = await page.query_selector( '.scheduler-status, #schedulerStatus, [class*="scheduler"]' ) has_scheduler = scheduler is not None start_btn = await page.query_selector( '#startSchedulerBtn, [onclick*="startScheduler"]' ) stop_btn = await page.query_selector( '#stopSchedulerBtn, [onclick*="stopScheduler"]' ) check_btn = await page.query_selector( '[onclick*="CheckAll"], button:has-text("Vérifier")' ) await page.screenshot( path=str(EVIDENCE_DIR / "04_scheduler_panel.png"), full_page=True ) results.append(("Scheduler panel displays", has_scheduler)) print( f"Scheduler: {has_scheduler}, Start btn: {start_btn is not None}, Stop btn: {stop_btn is not None}, Check btn: {check_btn is not None}" ) # Test 5: Test filter tabs (All/Active/Paused/Completed) print("\n=== Test 5: Test filter tabs ===") filter_tabs = await page.query_selector_all( '.filter-tabs .filter-tab, [class*="filter-tab"]' ) await page.screenshot( path=str(EVIDENCE_DIR / "05_filter_tabs.png"), full_page=True ) filter_names = [] for i, tab in enumerate(filter_tabs): try: tab_text = await tab.text_content() filter_names.append(tab_text.strip()) await tab.click() await page.wait_for_timeout(500) except Exception as e: print(f"Error clicking filter {i}: {e}") await page.screenshot( path=str(EVIDENCE_DIR / "05_filters_clicked.png"), full_page=True ) results.append(("Filter tabs present and clickable", len(filter_tabs) >= 4)) print(f"Found filter tabs: {filter_names}") # Test 6: Test settings modal print("\n=== Test 6: Test settings modal ===") settings_btn = await page.query_selector( 'button:has-text("Paramètres"), button:has-text("Settings"), [onclick*="settings"]' ) if settings_btn: await settings_btn.click() await page.wait_for_timeout(1000) await page.screenshot( path=str(EVIDENCE_DIR / "06_settings_open.png"), full_page=True ) # Close modal - try multiple methods modal_closed = False for selector in [ "#settingsModal button[onclick*='closeSettingsModal']", "#settingsModal button:has-text('×')", 'button:has-text("Fermer")', 'button:has-text("Close")', ]: try: close_btn = await page.query_selector(selector) if close_btn: await close_btn.click() modal_closed = True break except: continue # If still not closed, evaluate JS to close if not modal_closed: try: await page.evaluate("closeSettingsModal()") modal_closed = True except: pass if not modal_closed: await page.keyboard.press("Escape") modal_closed = False for selector in [ "#settingsModal button.close", '[class*="modal"] .close', 'button:has-text("Fermer")', 'button:has-text("Close")', ]: try: close_btn = await page.query_selector(selector) if close_btn: await close_btn.click() modal_closed = True break except: continue if not modal_closed: await page.keyboard.press("Escape") await page.wait_for_timeout(1000) await page.screenshot( path=str(EVIDENCE_DIR / "06_settings_closed.png"), full_page=True ) results.append(("Settings modal works", True)) print("Settings modal opened and closed") else: await page.screenshot( path=str(EVIDENCE_DIR / "06_settings_not_found.png"), full_page=True ) results.append(("Settings modal works", False)) print("Settings button not found") # Test 7: Verify 30-second status refresh print("\n=== Test 7: Check for refresh interval ===") page_content = await page.content() has_refresh = "setInterval" in page_content has_scheduler_interval = ( "loadSchedulerStatus" in page_content or "scheduler" in page_content.lower() ) await page.screenshot( path=str(EVIDENCE_DIR / "07_refresh_check.png"), full_page=True ) results.append( ("Refresh mechanism present", has_refresh or has_scheduler_interval) ) print( f"Has setInterval: {has_refresh}, Has scheduler refresh: {has_scheduler_interval}" ) # Test 8: Test tab switching print("\n=== Test 8: Test tab switching ===") try: # Force close any modal first await page.keyboard.press("Escape") await page.wait_for_timeout(500) home_tab = await page.query_selector('button.tab:has-text("Accueil")') if home_tab: await home_tab.click() await page.wait_for_timeout(1000) await page.screenshot( path=str(EVIDENCE_DIR / "08_home_tab.png"), full_page=True ) watchlist_tab = await page.query_selector( 'button.tab:has-text("Watchlist")' ) if watchlist_tab: await watchlist_tab.click() await page.wait_for_timeout(1000) await page.screenshot( path=str(EVIDENCE_DIR / "08_back_to_watchlist.png"), full_page=True ) results.append(("Tab switching works", True)) except Exception as e: print(f"Tab switching error: {e}") results.append(("Tab switching works", False)) # Test 9: Direct /web#watchlist URL print("\n=== Test 9: Test /web#watchlist URL ===") await page.goto(f"{BASE_URL}/web#watchlist") await page.wait_for_load_state("networkidle") await page.wait_for_timeout(2000) await page.screenshot( path=str(EVIDENCE_DIR / "09_web_hash_watchlist.png"), full_page=True ) watchlist_content = await page.query_selector( ".watchlist-container, #watchlistContainer" ) results.append( ("/web#watchlist loads watchlist", watchlist_content is not None) ) # Test 10: Test /watchlist redirect print("\n=== Test 10: Verify /watchlist returns content ===") await page.goto(f"{BASE_URL}/watchlist") await page.wait_for_load_state("networkidle") content = await page.content() has_watchlist_content = ( "watchlist" in content.lower() and "ma watchlist" in content.lower() ) results.append(("/watchlist page has content", has_watchlist_content)) # Print results print("\n" + "=" * 60) print("TEST RESULTS:") print("=" * 60) passed = 0 for name, result in results: status = "PASS" if result else "FAIL" print(f"[{status}] {name}") if result: passed += 1 print("=" * 60) print(f"Total: {passed}/{len(results)} tests passed") # Save results with open(EVIDENCE_DIR / "test_results.txt", "w") as f: f.write("Watchlist Integration Test Results\n") f.write("=" * 60 + "\n") for name, result in results: status = "PASS" if result else "FAIL" f.write(f"[{status}] {name}\n") f.write("=" * 60 + "\n") f.write(f"Total: {passed}/{len(results)} tests passed\n") await browser.close() return passed >= len(results) * 0.8 if __name__ == "__main__": success = asyncio.run(main()) exit(0 if success else 1)