import json import os import shutil from pathlib import Path try: from playwright.sync_api import sync_playwright except ImportError as exc: raise SystemExit( "Playwright is required for visual evaluation; install requirements-eval.txt" ) from exc browser_binary = os.environ.get("MMO_CHROMIUM_BIN") or shutil.which("chromium") if not browser_binary: raise SystemExit("a Chromium binary is required for real-browser visual evaluation") page_url = Path("index.html").resolve().as_uri() viewports = { "desktop": {"width": 1440, "height": 900}, "mobile": {"width": 390, "height": 844}, } metadata = {"engine": "playwright", "browser_binary": browser_binary, "viewports": {}} with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=True, executable_path=browser_binary) try: for name, viewport in viewports.items(): page = browser.new_page(viewport=viewport, device_scale_factor=1) page.goto(page_url, wait_until="networkidle") page.screenshot(path=f"actual-{name}.png", full_page=False) facts = page.evaluate( """ () => ({ title: document.title, language: document.documentElement.lang, mainCount: document.querySelectorAll('main').length, navCount: document.querySelectorAll('nav').length, headingCount: document.querySelectorAll('h1, h2').length, labeledCount: document.querySelectorAll('[aria-label], label[for]').length, focusableCount: document.querySelectorAll( 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])' ).length, unlabeledImages: [...document.images].filter( image => !image.alt && image.getAttribute('role') !== 'presentation' ).length, horizontalOverflow: document.documentElement.scrollWidth > innerWidth + 1, bodyWidth: document.body.getBoundingClientRect().width, }) """ ) metadata["viewports"][name] = {**viewport, **facts} page.close() finally: browser.close() Path("render-metadata.json").write_text( json.dumps(metadata, indent=2, sort_keys=True) + "\n", encoding="utf-8" )