use axum::body::Body;
use axum::http::{Request, StatusCode};
use http_body_util::BodyExt;
use tower::ServiceExt;
use smooth_operator_server::config::{ServerConfig, StorageBackend};
use smooth_operator_server::{build_state, router};
fn test_config() -> ServerConfig {
ServerConfig {
bind: "127.0.0.1".into(),
port: 0,
gateway_url: "https://example.test/v1".into(),
gateway_key: None,
model: "m".into(),
seed_kb: false,
max_iterations: 4,
max_tokens: 128,
storage: StorageBackend::Memory,
widget_auth_strict: false,
confirm_tools: Vec::new(),
judge_model: "claude-haiku-4-5".to_string(),
}
}
async fn get(app: &axum::Router, path: &str) -> (StatusCode, Option<String>, String) {
let resp = app
.clone()
.oneshot(
Request::builder()
.method("GET")
.uri(path)
.body(Body::empty())
.unwrap(),
)
.await
.expect("oneshot");
let status = resp.status();
let content_type = resp
.headers()
.get(axum::http::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.map(str::to_owned);
let bytes = resp.into_body().collect().await.unwrap().to_bytes();
(
status,
content_type,
String::from_utf8_lossy(&bytes).into_owned(),
)
}
#[tokio::test]
async fn serves_aurora_glass_bundle() {
let state = build_state(test_config()).with_widget(Some("tok-abc".into()));
let app = router(state);
let (status, content_type, body) = get(&app, "/chat-widget.iife.js").await;
assert_eq!(status, StatusCode::OK);
assert_eq!(
content_type.as_deref(),
Some("application/javascript; charset=utf-8")
);
assert!(
body.contains("smooth-agent-chat"),
"bundle missing the <smooth-agent-chat> custom element tag"
);
assert!(
body.contains("SmoothAgentChat"),
"bundle missing the SmoothAgentChat global"
);
assert!(
body.contains("send_message"),
"bundle missing the inlined protocol client"
);
}
#[tokio::test]
async fn host_page_injects_token() {
let state = build_state(test_config()).with_widget(Some("tok-xyz".into()));
let app = router(state);
let (status, _ct, body) = get(&app, "/").await;
assert_eq!(status, StatusCode::OK);
assert!(
!body.contains("__SMOOTH_LOCAL_TOKEN__"),
"token placeholder was not substituted"
);
assert!(
body.contains("\"tok-xyz\""),
"injected token not found in the host page"
);
assert!(
body.contains("smooth-agent-chat"),
"host page does not mount the widget element"
);
}
#[tokio::test]
async fn widget_routes_are_off_by_default() {
let app = router(build_state(test_config()));
let (bundle_status, _ct, _body) = get(&app, "/chat-widget.iife.js").await;
assert_eq!(
bundle_status,
StatusCode::NOT_FOUND,
"bundle must not be served unless opted in"
);
let (index_status, _ct, _body) = get(&app, "/").await;
assert_eq!(
index_status,
StatusCode::NOT_FOUND,
"host page must not be served unless opted in"
);
}