#!/usr/bin/env python3 """ Playwright test to debug modal click functionality on live LLM Monitor instance """ import asyncio import json from playwright.async_api import async_playwright TARGET_URL = "http://192.168.254.12:8000" async def test_modal_click(): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) context = await browser.new_context() page = await context.new_page() # Enable console logging page.on("console", lambda msg: print(f"[CONSOLE] {msg.type}: {msg.text}")) page.on("pageerror", lambda exc: print(f"[PAGE ERROR] {exc}")) print(f"\nšŸ” [TEST] Navigating to {TARGET_URL}...") await page.goto(TARGET_URL, wait_until="networkidle") # Wait for models to load print("[WAIT] Waiting for models container to populate...") try: await page.wait_for_selector("[data-model-key]", timeout=5000) print("āœ… [SUCCESS] Models loaded - found cards with data-model-key attribute") except Exception as e: print(f"āŒ [FAILURE] No models found: {e}") print("\nšŸ“‹ Page content:") content = await page.content() print(content[:2000]) await browser.close() return # Get all model cards cards = await page.query_selector_all("[data-model-key]") print(f"\nšŸ“Š Found {len(cards)} model cards") if len(cards) == 0: print("āŒ No cards found after waiting") await browser.close() return # Get first card info first_card = cards[0] model_key = await first_card.get_attribute("data-model-key") print(f"\nšŸŽÆ [TARGET] First card data-model-key: {model_key}") # Get modal state BEFORE click modal_before = await page.query_selector("#model-details-modal") if modal_before: hidden_class_before = await modal_before.get_attribute("class") is_hidden_before = "hidden" in (hidden_class_before or "") print(f"\nšŸ“ [BEFORE CLICK] Modal HTML class: '{hidden_class_before}'") print(f" Is hidden: {is_hidden_before}") else: print("\nāŒ [ERROR] Modal element #model-details-modal not found!") # Check if app is initialized app_exists = await page.evaluate("typeof window.llmMonitorApp !== 'undefined'") print(f" App initialized: {app_exists}") # Check localStorage localStorage = await page.evaluate("JSON.stringify(localStorage)") print(f" localStorage keys: {list(json.loads(localStorage).keys())}") # PERFORM CLICK print(f"\nšŸ–±ļø [CLICK] Clicking on model card...") await first_card.click() # Brief pause for DOM update await page.wait_for_timeout(500) # Get modal state AFTER click modal_after = await page.query_selector("#model-details-modal") if modal_after: hidden_class_after = await modal_after.get_attribute("class") is_hidden_after = "hidden" in (hidden_class_after or "") print(f"\nšŸ“ [AFTER CLICK] Modal HTML class: '{hidden_class_after}'") print(f" Is hidden: {is_hidden_after}") else: print("\nāŒ [ERROR] Modal element #model-details-modal not found after click!") # Evaluate if modal is visible is_visible = await page.evaluate(""" () => { const modal = document.getElementById('model-details-modal'); if (!modal) return 'NOT_FOUND'; const isHidden = modal.classList.contains('hidden'); const computedStyle = window.getComputedStyle(modal); return { hasHiddenClass: isHidden, display: computedStyle.display, visibility: computedStyle.visibility, opacity: computedStyle.opacity, zIndex: computedStyle.zIndex }; } """) print(f"\nšŸ’» [DOM CHECK] Modal computed state:\n {json.dumps(is_visible, indent=3)}") # Check for event listeners listeners = await page.evaluate(""" () => { const card = document.querySelector('[data-model-key]'); if (!card) return 'NO_CARDS'; // Try to trigger click manually via app if it exists if (window.llmMonitorApp && typeof window.llmMonitorApp.showModelDetails === 'function') { return 'APP_METHOD_EXISTS'; } return 'NO_APP_METHOD'; } """) print(f"\nšŸ”— [LISTENERS] Event handler state: {listeners}") # Take screenshot screenshot_path = "/tmp/modal-test-after-click.png" await page.screenshot(path=screenshot_path) print(f"\nšŸ“ø Screenshot saved: {screenshot_path}") # Final verdict print("\n" + "="*70) if hidden_class_before is not None and hidden_class_after is not None: if is_hidden_before and not is_hidden_after: print("āœ… [PASS] Modal successfully opened on click!") elif is_hidden_before and is_hidden_after: print("āŒ [FAIL] Modal still has 'hidden' class after click") print(" → Event handler may not be attached") print(" → app.js may not be loaded/initialized") else: print("āš ļø [UNCLEAR] Unexpected modal state") else: print("āŒ [ERROR] Could not compare modal states") print("="*70) await browser.close() if __name__ == "__main__": asyncio.run(test_modal_click())