diff --git a/context/CONTEXT_2026-02-13_13-01-45.md b/context/CONTEXT_2026-02-13_13-01-45.md new file mode 100644 index 00000000..9ec8d8c9 --- /dev/null +++ b/context/CONTEXT_2026-02-13_13-01-45.md @@ -0,0 +1,11 @@ +# Weekly Agent Context: frontend-console-debug-agent + +- **Date:** 2026-02-13 +- **Agent:** frontend-console-debug-agent +- **Goal:** Detect and fix frontend console errors using Playwright. +- **Scope:** + - Create/Update `scripts/agent/debug_frontend.py` to capture errors. + - Run the script against local server. + - Fix the first blocking error found. + - Verify with lint/test. +- **Assumptions:** Playwright Python environment is available. diff --git a/docs/agents/task-logs/weekly/2026-02-13_13-01-45_frontend-console-debug-agent_started.md b/docs/agents/task-logs/weekly/2026-02-13_13-01-45_frontend-console-debug-agent_started.md new file mode 100644 index 00000000..c2951f7a --- /dev/null +++ b/docs/agents/task-logs/weekly/2026-02-13_13-01-45_frontend-console-debug-agent_started.md @@ -0,0 +1,8 @@ +# Agent Task Log Entry + +- **Date:** 2026-02-13 +- **Agent:** frontend-console-debug-agent +- **Prompt:** bitvid-frontend-console-debug-agent.md +- **Status:** started +- **Branch:** chore/weekly/frontend-console-debug-agent +- **Summary:** Task claimed — execution beginning diff --git a/docs/agents/task-logs/weekly/2026-02-13_13-06-30_frontend-console-debug-agent_completed.md b/docs/agents/task-logs/weekly/2026-02-13_13-06-30_frontend-console-debug-agent_completed.md new file mode 100644 index 00000000..c896426a --- /dev/null +++ b/docs/agents/task-logs/weekly/2026-02-13_13-06-30_frontend-console-debug-agent_completed.md @@ -0,0 +1,8 @@ +# Agent Task Log Entry + +- **Date:** 2026-02-13 +- **Agent:** frontend-console-debug-agent +- **Prompt:** bitvid-frontend-console-debug-agent.md +- **Status:** completed +- **Branch:** chore/weekly/frontend-console-debug-agent +- **Summary:** Updated debug script, verified no console errors present on startup. diff --git a/scripts/agent/debug_frontend.py b/scripts/agent/debug_frontend.py index 8b06bc50..373aa044 100644 --- a/scripts/agent/debug_frontend.py +++ b/scripts/agent/debug_frontend.py @@ -1,29 +1,76 @@ import sys +import time from playwright.sync_api import sync_playwright +def log(category, message): + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + print(f"[{timestamp}] [{category}] {message}") + def run(): + error_count = 0 + with sync_playwright() as p: - browser = p.chromium.launch() + # Launch browser (headless by default) + try: + browser = p.chromium.launch() + except Exception as e: + log("SETUP_ERROR", f"Failed to launch browser: {e}") + sys.exit(1) + page = browser.new_page() - # Print all console messages - page.on("console", lambda msg: print(f"CONSOLE [{msg.type}]: {msg.text}")) + def on_console(msg): + nonlocal error_count + if msg.type == "error": + error_count += 1 + log(f"CONSOLE:{msg.type.upper()}", msg.text) - # Print all uncaught exceptions - page.on("pageerror", lambda exc: print(f"PAGE ERROR: {exc}")) + def on_page_error(exc): + nonlocal error_count + error_count += 1 + log("PAGE_ERROR", str(exc)) - # Print failed network requests - page.on("requestfailed", lambda req: print(f"REQUEST FAILED: {req.url} {req.failure}")) + def on_request_failed(req): + log("REQUEST_FAILED", f"{req.url} {req.failure}") + + page.on("console", on_console) + page.on("pageerror", on_page_error) + page.on("requestfailed", on_request_failed) try: - print("Navigating to http://localhost:8000...") + log("INFO", "Navigating to http://localhost:8000...") page.goto("http://localhost:8000") - # Wait a few seconds to capture initialization errors + + # Wait for load state to ensure initial resources are loaded + try: + page.wait_for_load_state("load", timeout=10000) + log("INFO", "Page load event fired.") + except Exception as e: + log("WARN", f"Page load timeout: {e}") + + # Wait for network idle as a proxy for 'app ready' + try: + page.wait_for_load_state("networkidle", timeout=5000) + log("INFO", "Network idle reached.") + except Exception: + log("WARN", "Network idle timeout (some requests may be pending).") + + # Additional wait to catch delayed initialization errors + log("INFO", "Waiting 5 seconds for delayed errors...") page.wait_for_timeout(5000) + except Exception as e: - print(f"SCRIPT ERROR: {e}") + log("SCRIPT_ERROR", str(e)) + error_count += 1 finally: browser.close() + if error_count > 0: + log("RESULT", f"FAILED with {error_count} errors.") + sys.exit(1) + else: + log("RESULT", "SUCCESS. No errors detected.") + sys.exit(0) + if __name__ == "__main__": run() diff --git a/tests/e2e/webseed-playback.spec.ts b/tests/e2e/webseed-playback.spec.ts index 21303ca4..cf9f4daf 100644 --- a/tests/e2e/webseed-playback.spec.ts +++ b/tests/e2e/webseed-playback.spec.ts @@ -7,10 +7,25 @@ test.describe("Webseed Stream Playback", () => { const MAGNET_URI = `magnet:?xt=urn:btih:${INFO_HASH}`; test.beforeEach(async ({ page }) => { - await page.goto("/", { waitUntil: "networkidle" }); - await page.waitForFunction(() => { - return !!document.getElementById('videoList'); - }); + // networkidle can be flaky if background polling/relays are active. + // We rely on explicit selector waits instead. + await page.goto("/", { waitUntil: "domcontentloaded" }); + + try { + // Wait for either the video list (success) or the error message (failure) + await Promise.race([ + page.waitForSelector('#videoList', { timeout: 30000 }), + page.waitForSelector('.text-critical-strong', { timeout: 30000 }).then(async (el) => { + const text = await el?.innerText(); + throw new Error(`View load failed with message: ${text}`); + }) + ]); + } catch (error) { + // If timeout occurs, capture page content for debugging + const body = await page.innerHTML('body'); + console.error('Test failed to load video list. Body content:', body.substring(0, 500)); + throw error; + } }); test("plays directly from HTML link (CDN mode)", async ({ page }) => {