Files
hermes-agent/tests/gateway/test_api_server_gui_mount.py
Alexander Whitestone 8e0f24db3f
Some checks failed
Forge CI / smoke-and-build (pull_request) Failing after 59s
feat(web-console): cherry-pick React web console GUI from gary-the-ai fork
Cherry-pick the Hermes Web Console from gary-the-ai/hermes-web-console-gui.
React + TypeScript frontend with Vite, Python aiohttp backend API.

Components:
- web_console/ — React frontend (chat, sessions, memory, settings, skills,
  gateway config, cron, workspace, tools, browser, insights pages)
- gateway/web_console/ — Python backend API (23 endpoints, SSE event bus,
  11 service modules)
- gateway/platforms/api_server_ui.py — embedded browser UI for API server
- gateway/platforms/api_server.py — route registration refactored into
  _register_routes(), web console mounted via maybe_register_web_console()
- run-gui.sh / setup-gui.sh — one-command launch and setup scripts
- tests/gateway/test_api_server_gui_mount.py — 4 integration tests (passing)
- tests/web_console/ — 13 backend test files (51 passing)
- docs/plans/ — implementation plan, API schema, frontend architecture

Fix: added missing ModelContextError class and CRON_MIN_CONTEXT_TOKENS to
cron/scheduler.py (pre-existing import bug).

Closes #325
2026-04-13 18:01:51 -04:00

85 lines
2.8 KiB
Python

"""Tests for Hermes Web Console routes mounted by the API server adapter."""
import pytest
from aiohttp import web
from aiohttp.test_utils import TestClient, TestServer
from gateway.config import PlatformConfig
from gateway.platforms.api_server import APIServerAdapter, cors_middleware
def _make_adapter() -> APIServerAdapter:
return APIServerAdapter(PlatformConfig(enabled=True))
def _create_app(adapter: APIServerAdapter) -> web.Application:
app = web.Application(middlewares=[cors_middleware])
adapter._register_routes(app)
return app
class TestGuiRoutes:
@pytest.mark.asyncio
async def test_gui_health_route_exists(self):
adapter = _make_adapter()
app = _create_app(adapter)
async with TestClient(TestServer(app)) as cli:
resp = await cli.get("/api/gui/health")
assert resp.status == 200
assert resp.content_type == "application/json"
data = await resp.json()
assert data == {
"status": "ok",
"service": "gui-backend",
"product": "hermes-web-console",
}
@pytest.mark.asyncio
async def test_gui_meta_route_exists(self):
adapter = _make_adapter()
app = _create_app(adapter)
async with TestClient(TestServer(app)) as cli:
resp = await cli.get("/api/gui/meta")
assert resp.status == 200
data = await resp.json()
assert data["product"] == "hermes-web-console"
assert data["api_base_path"] == "/api/gui"
assert data["app_base_path"] == "/app/"
assert data["adapter"] == adapter.name
@pytest.mark.asyncio
async def test_app_placeholder_route_exists(self):
adapter = _make_adapter()
app = _create_app(adapter)
async with TestClient(TestServer(app)) as cli:
resp = await cli.get("/app/")
assert resp.status == 200
assert resp.content_type == "text/html"
html = await resp.text()
assert "Hermes Web Console" in html
assert "/api/gui/health" in html
assert "/api/gui/meta" in html
@pytest.mark.asyncio
async def test_existing_routes_still_work_with_gui_mount(self):
adapter = _make_adapter()
app = _create_app(adapter)
async with TestClient(TestServer(app)) as cli:
root_resp = await cli.get("/")
health_resp = await cli.get("/health")
models_resp = await cli.get("/v1/models")
assert root_resp.status == 200
assert health_resp.status == 200
assert models_resp.status == 200
health_data = await health_resp.json()
models_data = await models_resp.json()
assert health_data["status"] == "ok"
assert models_data["data"][0]["id"] == "hermes-agent"