#!/usr/bin/env python3 """v2 regression: core browser.* parity methods with handle refs.""" import os import sys import time import urllib.parse from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from cmux import cmux, cmuxError SOCKET_PATH = os.environ.get("CMUX_SOCKET", "/tmp/cmux-debug.sock") def _must(cond: bool, msg: str) -> None: if not cond: raise cmuxError(msg) def main() -> int: with cmux(SOCKET_PATH) as c: ident = c.identify() focused = ident.get("focused") or {} _must(isinstance(focused, dict), f"identify.focused should be dict: {focused}") _must(bool(focused.get("workspace_id") or focused.get("workspace_ref")), f"identify should return workspace handle: {focused}") _must(bool(focused.get("surface_id") or focused.get("surface_ref")), f"identify should return surface handle: {focused}") # Open browser split and prefer ref handles to validate v2 handle parsing. opened = c._call("browser.open_split", {"url": "about:blank"}) or {} sid = opened.get("surface_id") sref = opened.get("surface_ref") _must(bool(sid), f"browser.open_split returned no surface_id: {opened}") target = str(sid) if sref: _ = c._call("browser.url.get", {"surface_id": str(sref)}) html = """ cmux-browser-p0
ready
""".strip() data_url = "data:text/html," + urllib.parse.quote(html) c._call("browser.navigate", {"surface_id": target, "url": data_url}) try: c._call("browser.wait", {"surface_id": target, "selector": "#btn", "timeout_ms": 5000}) except cmuxError as exc: if "timeout" not in str(exc): raise deadline = time.time() + 5.0 while time.time() < deadline: probe = c._call( "browser.eval", {"surface_id": target, "script": "document.querySelector('#btn') !== null"}, ) or {} if bool(probe.get("value")): break time.sleep(0.05) else: raise c._call("browser.fill", {"surface_id": target, "selector": "#name", "text": "cmux"}) c._call("browser.click", {"surface_id": target, "selector": "#btn"}) out = c._call("browser.get.text", {"surface_id": target, "selector": "#out"}) or {} _must("cmux" in str(out.get("value", "")), f"Expected #out text to include 'cmux': {out}") c._call("browser.check", {"surface_id": target, "selector": "#chk"}) checked = c._call("browser.is.checked", {"surface_id": target, "selector": "#chk"}) or {} _must(bool(checked.get("value")) is True, f"Expected checkbox checked: {checked}") c._call("browser.select", {"surface_id": target, "selector": "#sel", "value": "b"}) val = c._call("browser.get.value", {"surface_id": target, "selector": "#sel"}) or {} _must(str(val.get("value", "")) == "b", f"Expected select value 'b': {val}") eval_res = c._call("browser.eval", {"surface_id": target, "script": "document.querySelector('#name').value"}) or {} _must(str(eval_res.get("value", "")) == "cmux", f"Expected eval value 'cmux': {eval_res}") snap = c._call("browser.snapshot", {"surface_id": target}) or {} snapshot_text = str(snap.get("snapshot") or "") _must("cmux-browser-p0" in snapshot_text, f"Expected snapshot text to include page title: {snap}") refs = snap.get("refs") or {} _must(isinstance(refs, dict), f"Expected snapshot refs dict: {snap}") _must(any(str(key).startswith("e") for key in refs.keys()), f"Expected eN refs in snapshot: {snap}") # Focus and focus-state checks can be slightly asynchronous. c._call("browser.focus_webview", {"surface_id": target}) deadline = time.time() + 2.0 focused_ok = False while time.time() < deadline: is_focused = c._call("browser.is_webview_focused", {"surface_id": target}) or {} if bool(is_focused.get("focused")): focused_ok = True break time.sleep(0.05) _must(focused_ok, "Expected browser.is_webview_focused=true after browser.focus_webview") shot = c._call("browser.screenshot", {"surface_id": target}) or {} b64 = str(shot.get("png_base64") or "") _must(len(b64) > 100, f"Expected non-trivial screenshot payload: len={len(b64)}") print("PASS: browser.* P0 methods work on cmux webview with ref handles") return 0 if __name__ == "__main__": raise SystemExit(main())