evOo-local/infra/sandboxes/computer/test_page_browser.py
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

136 lines
6.4 KiB
Python

"""Offline protocol/error regressions for the live browser helper."""
import importlib.machinery
import importlib.util
from pathlib import Path
import struct
import os
import subprocess
import sys
import unittest
from unittest.mock import Mock, patch
loader = importlib.machinery.SourceFileLoader("page_browser", str(Path(__file__).with_name("rakazo-page-browser")))
spec = importlib.util.spec_from_loader(loader.name, loader)
helper = importlib.util.module_from_spec(spec)
loader.exec_module(helper)
class PageBrowserTest(unittest.TestCase):
def test_closed_stdin_cancels_helper_without_a_browser(self):
with subprocess.Popen([sys.executable, str(Path(__file__).with_name("rakazo-page-browser")), "snapshot", "{}"],
env={**os.environ, "RAKAZO_BROWSER_WATCH_STDIN": "1", "RAKAZO_CDP_PORT": "0"},
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
process.stdin.close()
self.assertEqual(process.wait(timeout=3), 130)
def test_closed_extended_frame_does_not_spin(self):
for partial in (b"\x81\x7e", b"\x81\x7f", b"\x81\x80"):
with self.subTest(partial=partial):
client = helper.CdpClient("ws://127.0.0.1:9222/test")
client._sock = Mock()
client._sock.recv.return_value = b""
client._buf.extend(partial)
with self.assertRaisesRegex(RuntimeError, "closed"):
client._read_frame()
def test_bounds_frame_before_reading_payload(self):
client = helper.CdpClient("ws://127.0.0.1:9222/test")
client._sock = Mock()
client._buf.extend(b"\x81\x7f" + struct.pack("!Q", 10_000_000))
with self.assertRaisesRegex(RuntimeError, "too large"):
client._read_frame()
client._sock.recv.assert_not_called()
def test_rejects_url_credentials_before_navigation(self):
client = Mock()
for url in ("http://example:fake-password@example.test", "https://example:fake-password@example.test"):
with self.assertRaisesRegex(RuntimeError, "credentials"):
helper.navigate(client, "session", url)
client.call.assert_not_called()
def test_rejects_navigation_error(self):
client = Mock()
client.call.return_value = {"errorText": "net::ERR_NAME_NOT_RESOLVED"}
with self.assertRaisesRegex(RuntimeError, "ERR_NAME_NOT_RESOLVED"):
helper.navigate(client, "session", "https://example.test")
def test_preserves_completed_actions_when_next_response_is_lost(self):
with patch.object(helper, "ensure_helpers"), patch.object(helper, "eval_json") as evaluate:
evaluate.side_effect = [True, {}, True, TimeoutError("lost response")]
result = helper.act(Mock(), "session", [
{"kind": "click", "ref": "first"}, {"kind": "click", "ref": "second"},
])
self.assertEqual(result["completed"], 1)
self.assertTrue(result["uncertain"])
self.assertFalse(result["ok"])
def test_rejects_missing_text_before_any_action(self):
with patch.object(helper, "ensure_helpers") as ensure:
with self.assertRaisesRegex(RuntimeError, "Text"):
helper.act(Mock(), "session", [{"kind": "fill", "ref": "first"}])
ensure.assert_not_called()
def test_discovery_cannot_leave_loopback_endpoint(self):
with patch.object(helper, "http_get_json", return_value={"webSocketDebuggerUrl": "ws://example.test:9222/session"}):
with self.assertRaisesRegex(RuntimeError, "Unexpected CDP"):
helper.discover_ws_url(9222)
def test_ensure_world_reuses_named_isolated_context(self):
client = helper.CdpClient("ws://127.0.0.1:9222/test")
calls = []
def fake_call(method, params=None, *, session_id=None, timeout_s=30.0):
calls.append(method)
if method == "Page.getFrameTree":
return {"frameTree": {"frame": {"id": "frame-1"}}}
if method == "Runtime.enable":
client._handle_event({
"method": "Runtime.executionContextCreated",
"sessionId": session_id,
"params": {
"context": {
"id": 42,
"name": helper.WORLD_NAME,
"auxData": {"frameId": "frame-1", "isDefault": False},
}
},
})
return {}
raise AssertionError(f"unexpected CDP call: {method}")
client.call = fake_call # type: ignore[method-assign]
helper.ensure_world(client, "session-a")
self.assertEqual(client.context_id, 42)
self.assertNotIn("Page.createIsolatedWorld", calls)
def test_context_lookup_rejects_default_foreign_and_unbound_contexts(self):
client = helper.CdpClient("ws://127.0.0.1:9222/test")
for aux, session in (({"frameId": "frame-1", "isDefault": True}, "session-a"),
({"frameId": "other-frame", "isDefault": False}, "session-a"),
({"frameId": "frame-1", "isDefault": False}, "session-b"),
({}, "session-a")):
client._handle_event({"method": "Runtime.executionContextCreated", "sessionId": session,
"params": {"context": {"id": 42, "name": helper.WORLD_NAME, "auxData": aux}}})
self.assertIsNone(client.find_world_context(helper.WORLD_NAME, "frame-1", "session-a"))
def test_ensure_world_creates_when_missing(self):
client = helper.CdpClient("ws://127.0.0.1:9222/test")
def fake_call(method, params=None, *, session_id=None, timeout_s=30.0):
if method == "Page.getFrameTree":
return {"frameTree": {"frame": {"id": "frame-1"}}}
if method == "Runtime.enable":
return {}
if method == "Page.createIsolatedWorld":
self.assertEqual(params["worldName"], helper.WORLD_NAME)
return {"executionContextId": 7}
raise AssertionError(f"unexpected CDP call: {method}")
client.call = fake_call # type: ignore[method-assign]
helper.ensure_world(client, "session-a")
self.assertEqual(client.context_id, 7)
if __name__ == "__main__":
unittest.main()