feat: feedback_api — screenshot_page with Playwright (graceful fallback)
This commit is contained in:
parent
ddcf78fe6c
commit
2f37ad3e26
2 changed files with 51 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ from pathlib import Path
|
|||
|
||||
import requests
|
||||
import yaml
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
_ROOT = Path(__file__).parent.parent
|
||||
_EMAIL_RE = re.compile(r"[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}")
|
||||
|
|
@ -192,3 +193,24 @@ def upload_attachment(
|
|||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json().get("browser_download_url", "")
|
||||
|
||||
|
||||
def screenshot_page(port: int | None = None) -> bytes | None:
|
||||
"""
|
||||
Capture a screenshot of the running Peregrine UI using Playwright.
|
||||
Returns PNG bytes, or None if Playwright is not installed or if capture fails.
|
||||
"""
|
||||
if port is None:
|
||||
port = int(os.environ.get("STREAMLIT_PORT", os.environ.get("STREAMLIT_SERVER_PORT", "8502")))
|
||||
|
||||
try:
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch()
|
||||
page = browser.new_page(viewport={"width": 1280, "height": 800})
|
||||
page.goto(f"http://localhost:{port}", timeout=10_000)
|
||||
page.wait_for_load_state("networkidle", timeout=10_000)
|
||||
png = page.screenshot(full_page=False)
|
||||
browser.close()
|
||||
return png
|
||||
except Exception:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -242,3 +242,32 @@ def test_upload_attachment_returns_url(mock_post, monkeypatch):
|
|||
}
|
||||
url = upload_attachment(42, b"\x89PNG", "screenshot.png")
|
||||
assert url == "https://example.com/assets/abc"
|
||||
|
||||
|
||||
# ── screenshot_page ───────────────────────────────────────────────────────────
|
||||
|
||||
def test_screenshot_page_returns_none_on_failure(monkeypatch):
|
||||
"""screenshot_page returns None gracefully when capture fails."""
|
||||
from scripts.feedback_api import screenshot_page
|
||||
# Patch sync_playwright to raise an exception (simulates any failure)
|
||||
import scripts.feedback_api as fapi
|
||||
def bad_playwright():
|
||||
raise RuntimeError("browser unavailable")
|
||||
monkeypatch.setattr(fapi, "sync_playwright", bad_playwright)
|
||||
result = screenshot_page(port=9999)
|
||||
assert result is None
|
||||
|
||||
|
||||
@patch("scripts.feedback_api.sync_playwright")
|
||||
def test_screenshot_page_returns_bytes(mock_pw):
|
||||
"""screenshot_page returns PNG bytes when playwright is available."""
|
||||
from scripts.feedback_api import screenshot_page
|
||||
fake_png = b"\x89PNG\r\n\x1a\n"
|
||||
mock_context = MagicMock()
|
||||
mock_pw.return_value.__enter__ = lambda s: mock_context
|
||||
mock_pw.return_value.__exit__ = MagicMock(return_value=False)
|
||||
mock_browser = mock_context.chromium.launch.return_value
|
||||
mock_page = mock_browser.new_page.return_value
|
||||
mock_page.screenshot.return_value = fake_png
|
||||
result = screenshot_page(port=8502)
|
||||
assert result == fake_png
|
||||
|
|
|
|||
Loading…
Reference in a new issue