agent-browser / tests /test_api.py
anileo1's picture
Add API tests and pytest fixtures
c2e2481
Raw
History Blame Contribute Delete
4.44 kB
import time
from unittest.mock import AsyncMock, patch
from fastapi.testclient import TestClient
MOCK_SCORES = {
"completeness": 1.0,
"confidence": 0.8,
"efficiency": 0.789,
"speed": 1.0,
"reliability": 1.0,
"overall": 0.847,
}
def _mock_result(found: bool = True, answer: str | None = "$99/month", error: str | None = None) -> dict:
return {
"found": found,
"confidence": 0.8 if found else 0.0,
"answer": answer,
"error": error,
"steps_taken": 5,
"duration_seconds": 30.0,
"errors_encountered": 0,
"scores": MOCK_SCORES if found else {
"completeness": 0.0,
"confidence": 0.0,
"efficiency": 0.789,
"speed": 1.0,
"reliability": 0.75,
"overall": 0.268,
},
"step_details": [
{"step": 1, "reasoning": "Navigate to URL", "code": "go_to('https://example.com')", "observations": "Page loaded", "error": None},
{"step": 2, "reasoning": "Look for pricing", "code": "click('Pricing')", "observations": "Found pricing page", "error": None},
] if found else [],
}
def _submit_and_wait(client: TestClient, url: str, tasks: list[str], mock_result: dict) -> dict:
"""Submit a job and poll until it completes. Returns the job dict."""
with patch("app.api.routes.run_agent_task", new_callable=AsyncMock, return_value=mock_result):
response = client.post("/api/browse", json={"url": url, "tasks": tasks})
assert response.status_code == 200
job_id = response.json()["job_id"]
# Poll until completed (background task runs quickly with mock)
for _ in range(20):
job = client.get(f"/api/jobs/{job_id}").json()
if job["status"] == "completed":
return job
time.sleep(0.1)
raise TimeoutError(f"Job {job_id} did not complete in time")
def test_health(client: TestClient) -> None:
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
def test_browse_returns_job_id(client: TestClient) -> None:
with patch("app.api.routes.run_agent_task", new_callable=AsyncMock, return_value=_mock_result()):
response = client.post(
"/api/browse",
json={"url": "https://example.com", "tasks": ["Find pricing"]},
)
assert response.status_code == 200
data = response.json()
assert "job_id" in data
assert data["status"] == "running"
def test_browse_job_completes(client: TestClient) -> None:
job = _submit_and_wait(client, "https://example.com", ["Find pricing"], _mock_result())
assert job["status"] == "completed"
assert len(job["results"]) == 1
result = job["results"][0]
assert result["found"] is True
assert result["answer"] == "$99/month"
assert result["scores"]["overall"] == 0.847
def test_browse_not_found(client: TestClient) -> None:
mock = _mock_result(found=False, answer=None, error="Could not locate pricing page")
job = _submit_and_wait(client, "https://example.com", ["Find pricing"], mock)
result = job["results"][0]
assert result["found"] is False
assert result["error"] == "Could not locate pricing page"
def test_browse_saves_to_db(client: TestClient) -> None:
_submit_and_wait(client, "https://example.com", ["Find contact email"], _mock_result(answer="support@example.com"))
response = client.get("/api/results")
assert response.status_code == 200
results = response.json()
assert len(results) >= 1
assert results[0]["answer"] == "support@example.com"
assert results[0]["score_overall"] == 0.847
def test_dashboard(client: TestClient) -> None:
_submit_and_wait(client, "https://example.com", ["Find pricing"], _mock_result())
response = client.get("/api/dashboard")
assert response.status_code == 200
data = response.json()
assert data["total_runs"] >= 1
assert "avg_scores" in data
assert "by_url" in data
assert "top_issues" in data
assert "recommendations" in data
def test_jobs_list(client: TestClient) -> None:
_submit_and_wait(client, "https://example.com", ["Find pricing"], _mock_result())
response = client.get("/api/jobs")
assert response.status_code == 200
jobs = response.json()
assert len(jobs) >= 1
assert jobs[0]["status"] == "completed"