#!/usr/bin/env python3 """Batch mobile/tablet screenshots with a reused codehelper browser session.""" from __future__ import annotations import json import subprocess import sys from pathlib import Path ROOT = Path(r"F:\laragon\www\_MY\descrybe-v2") OUT = ROOT / "apps" / "web" / "static" / ".audit" BASE = "http://localhost:28472" PAGES = [ ("02-login", "/login", True), ("03-dashboard", "/dashboard", False), ("04-settings", "/settings", False), ("05-billing", "/billing", False), ("06-support", "/support", False), ("07-support-new", "/support/new", False), ("08-admin", "/admin", False), ("09-admin-billing", "/admin/billing", False), ("10-admin-support", "/admin/support", False), ("11-admin-users", "/admin/users", False), ("12-admin-settings", "/admin/settings", False), ] def run(cmd: list[str]) -> subprocess.CompletedProcess[str]: print(">", " ".join(cmd[:8]), "...") r = subprocess.run(cmd, capture_output=True, text=True) if r.stdout: print(r.stdout[-2000:] if len(r.stdout) > 2000 else r.stdout) if r.stderr: print(r.stderr[-2000:] if len(r.stderr) > 2000 else r.stderr, file=sys.stderr) return r def main() -> int: OUT.mkdir(parents=True, exist_ok=True) login_actions = json.dumps( [ {"action": "wait_hydrate"}, { "action": "fill", "selector": "input[type=email],input[name=email],#email", "text": "demo@descrybe.local", }, { "action": "fill", "selector": "input[type=password],input[name=password],#password", "text": "DemoPass123!", }, {"action": "click", "selector": "button[type=submit]"}, {"action": "wait_nav"}, {"action": "wait_hydrate"}, {"action": "wait", "ms": 1500}, # dismiss cookies if present {"action": "click", "selector": "button:has-text('Accept all'), [data-testid=cookie-consent-banner] button:nth-of-type(3)"}, {"action": "wait", "ms": 500}, ] ) for device in ("mobile", "tablet"): session = f"audit-{device}" # login once per device r = run( [ "codehelper", "browser", "test", f"{BASE}/login", "--device", device, "--format", "png", "--wait-hydrate", "--session", session, "--session-clear", "--actions", login_actions, "-o", str(OUT / f"00-post-login-{device}.png"), "--path", str(ROOT), ] ) if r.returncode != 0: print(f"login failed for {device}", file=sys.stderr) return r.returncode for slug, path, public in PAGES: if path == "/login": # public unauth shot (separate short session not needed — skip for auth device) continue actions = json.dumps( [ {"action": "navigate", "url": f"{BASE}{path}"}, {"action": "wait_hydrate"}, {"action": "wait", "ms": 1200}, ] ) out = OUT / f"{slug}-{device}.png" r = run( [ "codehelper", "browser", "test", f"{BASE}{path}", "--device", device, "--format", "png", "--wait-hydrate", "--session", session, "--actions", actions, "-o", str(out), "--path", str(ROOT), "--snapshot", ] ) print(f"{slug} {device} exit={r.returncode} -> {out.exists()}") # nav open on dashboard nav_actions = json.dumps( [ {"action": "navigate", "url": f"{BASE}/dashboard"}, {"action": "wait_hydrate"}, {"action": "click", "selector": 'button[aria-label="Open navigation"], [data-tour=nav-mobile-toggle]'}, {"action": "wait", "ms": 800}, ] ) r = run( [ "codehelper", "browser", "test", f"{BASE}/dashboard", "--device", device, "--format", "png", "--wait-hydrate", "--session", session, "--actions", nav_actions, "-o", str(OUT / f"13-nav-open-{device}.png"), "--path", str(ROOT), ] ) print(f"nav-open {device} exit={r.returncode}") # public login (no session) for device in ("mobile", "tablet"): run( [ "codehelper", "browser", "test", f"{BASE}/login", "--device", device, "--format", "png", "--wait-hydrate", "-o", str(OUT / f"02-login-{device}.png"), "--path", str(ROOT), ] ) return 0 if __name__ == "__main__": raise SystemExit(main())