74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
"""Unit tests for the dynamic rendering path (#92): fetch_url(render=True)."""
|
|
|
|
import pytest
|
|
|
|
import backend.tools.web as web
|
|
from backend.tools import webrender
|
|
from backend.tools.context import ToolContext, ToolError, ToolMode
|
|
from backend.tools.registry import get_tool
|
|
|
|
|
|
def _ctx() -> ToolContext:
|
|
return ToolContext(user={"username": "tester", "vaults": []}, mode=ToolMode.IN_APP)
|
|
|
|
|
|
class TestRegistration:
|
|
def test_render_param_exposed_in_schema(self):
|
|
spec = get_tool("fetch_url")
|
|
assert spec is not None
|
|
assert "render" in spec.input_model.model_fields
|
|
|
|
|
|
class TestRenderUnavailable:
|
|
def test_missing_playwright_clear_error(self, monkeypatch):
|
|
monkeypatch.setattr(webrender, "_playwright_available", lambda: False)
|
|
with pytest.raises(ToolError) as ei:
|
|
web.fetch_url(_ctx(), web.FetchUrlInput(
|
|
url="https://example.com/spa", render=True))
|
|
assert ei.value.code == "playwright_unavailable"
|
|
|
|
def test_ssrf_guard_applied_before_render(self, monkeypatch):
|
|
monkeypatch.setattr(webrender, "_playwright_available", lambda: True)
|
|
with pytest.raises(ToolError) as ei:
|
|
web.fetch_url(_ctx(), web.FetchUrlInput(
|
|
url="http://127.0.0.1:9222/devtools", render=True))
|
|
assert ei.value.code in ("ssrf_blocked", "dns_error")
|
|
|
|
|
|
class TestRenderSuccess:
|
|
def test_fetch_url_delegates_to_worker(self, monkeypatch):
|
|
captured = {}
|
|
|
|
def fake_render(url):
|
|
captured["url"] = url
|
|
return {"url": url, "status": 200, "title": "SPA",
|
|
"text": "dynamic content", "rendered": True, "truncated": False}
|
|
|
|
monkeypatch.setattr(webrender, "render_page", fake_render)
|
|
out = web.fetch_url(_ctx(), web.FetchUrlInput(
|
|
url="https://example.com/spa", render=True))
|
|
assert captured["url"] == "https://example.com/spa"
|
|
assert out["rendered"] is True
|
|
assert "dynamic content" in out["text"]
|
|
|
|
def test_worker_failure_maps_to_tool_error(self, monkeypatch):
|
|
monkeypatch.setattr(webrender, "_playwright_available", lambda: True)
|
|
|
|
def boom(url):
|
|
raise RuntimeError("chromium crashed")
|
|
|
|
# The executor re-raises the worker exception on .result(); render_page
|
|
# must wrap it into a ToolError instead of leaking a bare exception.
|
|
monkeypatch.setattr(webrender, "_render_in_worker", boom)
|
|
with pytest.raises(ToolError) as ei:
|
|
web.fetch_url(_ctx(), web.FetchUrlInput(
|
|
url="https://example.com/spa", render=True))
|
|
assert ei.value.code == "render_unavailable"
|
|
|
|
|
|
class TestMarkdownExtraction:
|
|
def test_html_to_text_reused(self):
|
|
text = webrender._html_to_text("<html><body><p>hello</p><script>x()</script></body></html>")
|
|
assert "hello" in text
|
|
assert "x()" not in text
|