use axum::response::Html;
const WEB_CHAT_HTML: &str = include_str!("web_chat.html");
#[utoipa::path(
get,
path = "/web",
tag = "config",
responses((status = 200, description = "Browser chat surface over /api/v1/sessions/chat"))
)]
pub async fn web_chat_page() -> Html<&'static str> {
Html(WEB_CHAT_HTML)
}
#[cfg(test)]
mod web_chat_tests {
use super::*;
use crate::daemon::state::DaemonState;
use axum::body::Body;
use axum::http::{Request, StatusCode};
use std::sync::Arc;
use tower::ServiceExt;
#[tokio::test]
async fn web_chat_page_serves_html() {
let Html(body) = web_chat_page().await;
assert!(!body.is_empty(), "embedded page must not be empty");
assert!(body.contains("<!DOCTYPE html>"), "must be an HTML document");
assert!(
body.contains(crate::daemon::api::coordinator_routes::COORDINATOR_CHAT_PATH),
"page must POST to the chat-core endpoint"
);
assert!(
body.contains("actions: true") || body.contains("actions:true"),
"page must opt into the action-capable loop"
);
assert!(
body.contains("actions_taken"),
"page must render the audit trail"
);
assert!(
body.contains("conv_id"),
"page must continue the SM rolling context via conv_id"
);
}
#[tokio::test]
async fn web_route_returns_200_html() {
let state = Arc::new(DaemonState::new());
let app = crate::daemon::api::router(state);
let resp = app
.oneshot(
Request::builder()
.uri("/web")
.body(Body::empty())
.expect("request builds"),
)
.await
.expect("router serves /web");
assert_eq!(resp.status(), StatusCode::OK);
let ctype = resp
.headers()
.get(axum::http::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.unwrap_or_default();
assert!(
ctype.starts_with("text/html"),
"expected text/html, got {ctype:?}"
);
}
#[test]
fn web_chat_path_is_registered() {
use crate::daemon::api::coordinator_routes::COORDINATOR_CHAT_PATH;
let needle = format!("fetch(\"{COORDINATOR_CHAT_PATH}\"");
assert!(
WEB_CHAT_HTML.contains(&needle),
"web_chat.html must fetch the shared COORDINATOR_CHAT_PATH ({COORDINATOR_CHAT_PATH:?}) \
that api::router registers; route/HTML drift would otherwise 404"
);
}
#[test]
fn web_chat_renders_actions_taken_array() {
assert!(
WEB_CHAT_HTML.contains("Array.isArray(data.actions_taken)"),
"web_chat.html must check Array.isArray(data.actions_taken) before rendering"
);
assert!(
WEB_CHAT_HTML.contains("appendActions(data.actions_taken"),
"web_chat.html must pass actions_taken to appendActions for rendering"
);
}
#[test]
fn web_chat_stores_and_resends_conv_id() {
assert!(
WEB_CHAT_HTML.contains("convId = data.conv_id"),
"web_chat.html must store data.conv_id in convId for continuity"
);
assert!(
WEB_CHAT_HTML.contains("body.conv_id = convId"),
"web_chat.html must re-send convId as body.conv_id on the next turn"
);
}
}