Files
openswarm/backend/tests/test_api_dashboards.py
Arnav Naval 5cc9f6f01a [arnav] remove 6 dead HTTP endpoints
Verified each had no production caller (frontend, electron, or
internal backend) — only test references kept them looking alive
to coverage tools. Drops ~140 LOC of route handlers + helpers.
- POST /api/outputs/vibe-code: never wired up; frontend has no
  vibe-code UI. Also drops VibeCodeRequest model and
  VIBE_CODE_SYSTEM_PROMPT.
- GET /api/service/cost-breakdown: frontend Usage page reads
  /usage-summary, which already returns by_model/by_provider.
- GET /api/service/status: zero callers; was placeholder.
- GET /api/service/spool/count: debug-only, no UI surface.
- GET /api/settings/default-system-prompt: frontend defines its
  own DEFAULT_SYSTEM_PROMPT in settingsSlice.ts and never fetches
  the backend constant.
- POST /api/browser/command: sole caller (browser_mcp_server.py
  subprocess) was deleted in 8286cc1; browser_agent.py now calls
  ws_manager.send_browser_command directly in-process.
Tests covering the removed endpoints are dropped along with the
now-unused mock-anthropic helpers in test_api_outputs.py.
2026-05-06 17:11:57 -05:00

163 lines
5.2 KiB
Python

"""CRUD smoke for /api/dashboards.
Dashboards are the spatial canvas units. Each holds a `DashboardLayout`
(positions for agent/view/browser cards + sticky notes). Sessions are
tagged with `dashboard_id` so deleting a dashboard cascades into its
sessions.
Tests:
- lifespan migration creates "Dashboard 1" on a fresh boot
- create / get / update (name + layout) / duplicate / delete round-trip
- delete cascades into SESSIONS_DIR (sessions tagged with the
dashboard id are removed from disk)
- seed-demo lays down a session JSON with two messages
"""
from __future__ import annotations
import json
import os
def test_lifespan_seeds_default_dashboard(client):
"""First boot with no existing dashboards creates 'Dashboard 1'."""
resp = client.get("/api/dashboards/list")
assert resp.status_code == 200
items = resp.json()["dashboards"]
assert len(items) >= 1
assert any(d["name"] == "Dashboard 1" for d in items)
def test_create_get_update_delete_dashboard(client):
create = client.post(
"/api/dashboards/create",
json={"name": "Project Alpha"},
)
assert create.status_code == 200
dashboard_id = create.json()["id"]
fetched = client.get(f"/api/dashboards/{dashboard_id}")
assert fetched.status_code == 200
assert fetched.json()["name"] == "Project Alpha"
# Renaming flips auto_named → False (per dashboards.py:275).
update = client.put(
f"/api/dashboards/{dashboard_id}",
json={"name": "Project Beta"},
)
assert update.status_code == 200
body = update.json()
assert body["name"] == "Project Beta"
assert body["auto_named"] is False
deleted = client.delete(f"/api/dashboards/{dashboard_id}")
assert deleted.status_code == 200
gone = client.get(f"/api/dashboards/{dashboard_id}")
assert gone.status_code == 404
def test_dashboard_layout_field_round_trip(client):
"""PUT the `layout` field on a dashboard with a sticky note and
assert it survives a re-fetch via /api/dashboards/{id}.
Named `_field_` (not `_dashboard_layout_`) to make clear this exercises
the `layout` attribute of the live `Dashboard` model — not the legacy
`backend.apps.dashboard_layout` package, which was removed.
"""
create = client.post("/api/dashboards/create", json={"name": "L"})
dashboard_id = create.json()["id"]
layout = {
"cards": {},
"view_cards": {},
"browser_cards": {},
"notes": {
"n1": {
"note_id": "n1",
"x": 100,
"y": 200,
"width": 240,
"height": 200,
"content": "test note",
"color": "yellow",
}
},
"expanded_session_ids": [],
}
resp = client.put(
f"/api/dashboards/{dashboard_id}",
json={"layout": layout},
)
assert resp.status_code == 200
refetched = client.get(f"/api/dashboards/{dashboard_id}")
assert refetched.json()["layout"]["notes"]["n1"]["content"] == "test note"
def test_duplicate_dashboard(client):
create = client.post("/api/dashboards/create", json={"name": "Source"})
dashboard_id = create.json()["id"]
dup = client.post(f"/api/dashboards/{dashboard_id}/duplicate")
assert dup.status_code == 200
body = dup.json()
assert body["id"] != dashboard_id
assert body["name"] == "Source (copy)"
def test_delete_dashboard_cascades_to_sessions(client):
"""Sessions tagged with dashboard_id must be removed on delete.
Drops a fake session file straight onto SESSIONS_DIR (no agent
spawn needed) and verifies the cascade in `delete_dashboard`.
"""
from backend.config.paths import SESSIONS_DIR
create = client.post("/api/dashboards/create", json={"name": "Cascade"})
dashboard_id = create.json()["id"]
os.makedirs(SESSIONS_DIR, exist_ok=True)
session_id = "fake-session-cascade"
session_path = os.path.join(SESSIONS_DIR, f"{session_id}.json")
with open(session_path, "w") as f:
json.dump(
{
"id": session_id,
"name": "junk",
"dashboard_id": dashboard_id,
"messages": [],
"branches": {},
"active_branch_id": "main",
"created_at": "2026-01-01T00:00:00",
},
f,
)
assert os.path.exists(session_path)
deleted = client.delete(f"/api/dashboards/{dashboard_id}")
assert deleted.status_code == 200
assert not os.path.exists(session_path), (
"session file tagged with deleted dashboard should be removed"
)
def test_seed_demo_creates_session(client):
from backend.config.paths import SESSIONS_DIR
create = client.post("/api/dashboards/create", json={"name": "Demo"})
dashboard_id = create.json()["id"]
resp = client.post(f"/api/dashboards/{dashboard_id}/seed-demo")
assert resp.status_code == 200
session_id = resp.json()["session_id"]
session_path = os.path.join(SESSIONS_DIR, f"{session_id}.json")
assert os.path.exists(session_path)
with open(session_path) as f:
data = json.load(f)
assert data["dashboard_id"] == dashboard_id
assert len(data["messages"]) == 2 # canned welcome conversation