feat(ai): ecosysteme d'outils phase 2 - recherche a cle, cache/retry, Playwright, crawl, Gitea/GitHub, documents (#92)
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user