Skip to content

Commit a4942bf

Browse files
committed
Add test cases for hotfix-web-ui
1 parent a47b2ff commit a4942bf

4 files changed

Lines changed: 108 additions & 5 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hotfix-web-ui/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,9 @@ mime_guess = { workspace = true }
2424
rust-embed = { workspace = true, features = ["axum-ex"] }
2525
thiserror = { workspace = true }
2626

27+
[dev-dependencies]
28+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
29+
tower = { workspace = true }
30+
2731
[lints]
2832
workspace = true

crates/hotfix-web-ui/src/lib.rs

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ pub trait SessionInfoProvider: Clone + Send + Sync {
1919

2020
/// Build a router for the dashboard UI
2121
///
22-
/// This returns a router that works with any state `S` where you can
23-
/// extract a `P: SessionInfoProvider` using `axum::extract::FromRef`.
24-
///
25-
/// Typically, your state will be a struct with a `controller` field.
22+
/// This requires router state that can serve the required data
23+
/// to the endpoints as defined in [`SessionInfoProvider`].
2624
pub fn build_ui_router<S, P>() -> Router<S>
2725
where
2826
S: Clone + Send + Sync + 'static,
@@ -33,3 +31,102 @@ where
3331
.route("/", get(dashboard::dashboard_handler::<S, P>))
3432
.route("/static/{*file}", get(assets::static_handler))
3533
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
use super::*;
38+
use axum::body::Body;
39+
use axum::http::{Request, StatusCode};
40+
use hotfix::session::{SessionInfo, Status};
41+
use tower::ServiceExt;
42+
43+
#[derive(Clone)]
44+
struct MockSessionProvider {
45+
session_info: SessionInfo,
46+
}
47+
48+
#[async_trait::async_trait]
49+
impl SessionInfoProvider for MockSessionProvider {
50+
async fn get_session_info(&self) -> anyhow::Result<SessionInfo> {
51+
Ok(self.session_info.clone())
52+
}
53+
}
54+
55+
fn create_test_app() -> Router {
56+
let provider = MockSessionProvider {
57+
session_info: SessionInfo {
58+
next_sender_seq_number: 42,
59+
next_target_seq_number: 100,
60+
status: Status::Active,
61+
},
62+
};
63+
build_ui_router::<MockSessionProvider, MockSessionProvider>().with_state(provider)
64+
}
65+
66+
#[tokio::test]
67+
async fn test_dashboard_returns_html() {
68+
let app = create_test_app();
69+
70+
let response = app
71+
.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
72+
.await
73+
.unwrap();
74+
75+
assert_eq!(response.status(), StatusCode::OK);
76+
77+
let content_type = response
78+
.headers()
79+
.get("content-type")
80+
.and_then(|v| v.to_str().ok());
81+
assert!(
82+
content_type.is_some_and(|ct| ct.contains("text/html")),
83+
"Expected HTML content type"
84+
);
85+
}
86+
87+
#[tokio::test]
88+
async fn test_static_asset_returns_file() {
89+
let app = create_test_app();
90+
91+
let response = app
92+
.oneshot(
93+
Request::builder()
94+
.uri("/static/tailwind.js")
95+
.body(Body::empty())
96+
.unwrap(),
97+
)
98+
.await
99+
.unwrap();
100+
101+
assert_eq!(response.status(), StatusCode::OK);
102+
103+
let content_type = response
104+
.headers()
105+
.get("content-type")
106+
.and_then(|v| v.to_str().ok());
107+
assert!(
108+
content_type.is_some_and(
109+
|ct| ct.contains("javascript") || ct.contains("application/x-javascript")
110+
),
111+
"Expected JavaScript content type, got: {:?}",
112+
content_type
113+
);
114+
}
115+
116+
#[tokio::test]
117+
async fn test_static_asset_not_found() {
118+
let app = create_test_app();
119+
120+
let response = app
121+
.oneshot(
122+
Request::builder()
123+
.uri("/static/nonexistent.js")
124+
.body(Body::empty())
125+
.unwrap(),
126+
)
127+
.await
128+
.unwrap();
129+
130+
assert_eq!(response.status(), StatusCode::NOT_FOUND);
131+
}
132+
}

crates/hotfix/tests/common/actions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn when<T>(target: T) -> When<T> {
1313

1414
impl When<&SessionSpy> {
1515
pub async fn requests_disconnect(self) {
16-
self.target.session_handle().shutdown(false).await;
16+
self.target.session_handle().shutdown(false).await.unwrap();
1717
}
1818

1919
pub async fn sends_message(self, message: TestMessage) {

0 commit comments

Comments
 (0)