# /// script # requires-python = ">=3.11" # dependencies = ["playwright"] # /// """Browser end-to-end test: taps "📍 Here" (with a faked GPS fix), waits for the coach's streamed advice and the route map, asks a follow-up, and saves screenshots. uv run scripts/e2e.py [--url http://127.0.0.1:3000] [--dark] [--mobile] """ import argparse, sys from playwright.sync_api import sync_playwright, expect p = argparse.ArgumentParser() p.add_argument("--url", default="http://127.0.0.1:3000") p.add_argument("--channel", default="msedge", help="installed browser: chrome, msedge, ...") p.add_argument("--out", default="docs") p.add_argument("--dark", action="store_true") p.add_argument("--mobile", action="store_true") p.add_argument("--lat", type=float, default=51.0543) p.add_argument("--lon", type=float, default=3.7174) args = p.parse_args() name = "screenshot" + ("-mobile" if args.mobile else "") + ("-dark" if args.dark else "") viewport = {"width": 400, "height": 860} if args.mobile else {"width": 1000, "height": 900} with sync_playwright() as pw: browser = pw.chromium.launch(channel=args.channel, headless=True) ctx = browser.new_context( viewport=viewport, color_scheme="dark" if args.dark else "light", geolocation={"latitude": args.lat, "longitude": args.lon}, permissions=["geolocation"], device_scale_factor=2, ) page = ctx.new_page() errors = [] page.on("pageerror", lambda e: errors.append(str(e))) page.goto(args.url) page.evaluate("localStorage.clear()") page.reload() expect(page.locator("#health .dot.ok")).to_be_visible(timeout=10_000) page.get_by_text("🔥 Hard").click() page.get_by_text("📍 Here").click() # locates and submits expect(page.locator(".weather")).to_be_visible(timeout=20_000) expect(page.locator(".score.picked")).to_be_visible() expect(page.locator("#thread .markdown")).to_be_visible(timeout=180_000) if page.locator(".score.indoor.picked").count() == 0: expect(page.locator(".routes .map.leaflet-container")).to_be_visible(timeout=60_000) page.wait_for_timeout(1500) # tiles page.screenshot(path=f"{args.out}/{name}.png", full_page=True) page.get_by_text("⏱️ Only 30 min").click() expect(page.locator("#thread .markdown")).to_have_count(2, timeout=180_000) replies = page.locator("#thread .markdown").all_inner_texts() print("--- plan ---\n" + replies[0] + "\n--- follow-up ---\n" + replies[1]) page.reload() # the plan survives a reload expect(page.locator("#thread .markdown")).to_have_count(2) browser.close() if errors: print("page errors:", errors, file=sys.stderr) sys.exit(1) print(f"ok: {args.out}/{name}.png")