feat(browser): auto-commit con 60 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
"""Tests para cdp_eval.
|
||||
|
||||
Como cdp_eval requiere un Chrome vivo con remote debugging, se mockean las dos
|
||||
fronteras de I/O:
|
||||
- urllib.request.urlopen -> devuelve un /json con 2 targets (uno whatsapp).
|
||||
- websocket.create_connection -> un fake que responde al id==1 con un value.
|
||||
"""
|
||||
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
import urllib.request
|
||||
|
||||
import websocket
|
||||
|
||||
from browser.cdp_eval import cdp_eval
|
||||
|
||||
|
||||
# --- Fakes -----------------------------------------------------------------
|
||||
|
||||
def _targets_json():
|
||||
"""Dos targets de tipo page: uno de Google, otro de WhatsApp Web."""
|
||||
return [
|
||||
{
|
||||
"type": "page",
|
||||
"url": "https://www.google.com/",
|
||||
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/GOOGLE",
|
||||
},
|
||||
{
|
||||
"type": "page",
|
||||
"url": "https://web.whatsapp.com/",
|
||||
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/page/WA",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class _FakeHTTPResponse:
|
||||
"""Context manager que imita la respuesta de urlopen con .read()."""
|
||||
|
||||
def __init__(self, payload):
|
||||
self._buf = io.BytesIO(json.dumps(payload).encode())
|
||||
|
||||
def read(self):
|
||||
return self._buf.read()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
return False
|
||||
|
||||
|
||||
class _FakeWS:
|
||||
"""WebSocket fake: guarda el ws_url usado y responde al evaluate con value.
|
||||
|
||||
Antes de la respuesta con id==1, emite un evento intermedio (sin id) para
|
||||
verificar que cdp_eval drena eventos hasta encontrar su respuesta.
|
||||
"""
|
||||
|
||||
last_url = None
|
||||
|
||||
def __init__(self, url, value):
|
||||
_FakeWS.last_url = url
|
||||
self._value = value
|
||||
self._queue = []
|
||||
|
||||
def send(self, raw):
|
||||
msg = json.loads(raw)
|
||||
if msg.get("id") == 1:
|
||||
# Primero un evento de CDP sin id (debe drenarse), luego la respuesta.
|
||||
self._queue.append(json.dumps({
|
||||
"method": "Runtime.consoleAPICalled",
|
||||
"params": {"type": "log"},
|
||||
}))
|
||||
self._queue.append(json.dumps({
|
||||
"id": 1,
|
||||
"result": {"result": {"type": "string", "value": self._value}},
|
||||
}))
|
||||
|
||||
def recv(self):
|
||||
if self._queue:
|
||||
return self._queue.pop(0)
|
||||
return ""
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
# --- Tests -----------------------------------------------------------------
|
||||
|
||||
def test_golden_selecciona_target_por_substr_y_devuelve_value(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
urllib.request, "urlopen",
|
||||
lambda url, timeout=5: _FakeHTTPResponse(_targets_json()),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
websocket, "create_connection",
|
||||
lambda url, timeout=10.0: _FakeWS(url, "WhatsApp"),
|
||||
)
|
||||
|
||||
res = cdp_eval("document.title", port=9222, target_url_substr="whatsapp")
|
||||
|
||||
assert res["ok"] is True
|
||||
assert res["value"] == "WhatsApp"
|
||||
assert res["error"] == ""
|
||||
assert res["target_url"] == "https://web.whatsapp.com/"
|
||||
# Confirma que eligio el target whatsapp, no el de google.
|
||||
assert _FakeWS.last_url.endswith("/WA")
|
||||
|
||||
|
||||
def test_edge_substr_sin_match_devuelve_ok_false(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
urllib.request, "urlopen",
|
||||
lambda url, timeout=5: _FakeHTTPResponse(_targets_json()),
|
||||
)
|
||||
# create_connection no deberia llamarse; si lo hace, revienta el test.
|
||||
monkeypatch.setattr(
|
||||
websocket, "create_connection",
|
||||
lambda *a, **k: (_ for _ in ()).throw(AssertionError("no debe conectar")),
|
||||
)
|
||||
|
||||
res = cdp_eval("document.title", port=9222, target_url_substr="nope-no-existe")
|
||||
|
||||
assert res["ok"] is False
|
||||
assert res["value"] is None
|
||||
assert "no target matching" in res["error"]
|
||||
assert "nope-no-existe" in res["error"]
|
||||
assert res["target_url"] == ""
|
||||
|
||||
|
||||
def test_error_urlopen_lanza_devuelve_ok_false(monkeypatch):
|
||||
def _boom(url, timeout=5):
|
||||
raise OSError("connection refused")
|
||||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", _boom)
|
||||
|
||||
res = cdp_eval("document.title", port=9222, target_url_substr="whatsapp")
|
||||
|
||||
assert res["ok"] is False
|
||||
assert res["value"] is None
|
||||
assert "connection refused" in res["error"]
|
||||
assert res["target_url"] == ""
|
||||
Reference in New Issue
Block a user