mod common;
use axum::http::StatusCode;
use common::*;
use what_core::server::create_router;
#[tokio::test]
async fn root_index_returns_200() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("<h1>Home</h1>");
}
#[tokio::test]
async fn exact_page_match() {
let proj = TestProject::new();
proj.add_page("about.html", "<h1>About Us</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/about").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("<h1>About Us</h1>");
}
#[tokio::test]
async fn nested_page_match() {
let proj = TestProject::new();
proj.add_page("admin/users.html", "<h1>User List</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/admin/users").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("<h1>User List</h1>");
}
#[tokio::test]
async fn directory_index_fallback() {
let proj = TestProject::new();
proj.add_page("admin/index.html", "<h1>Admin Dashboard</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/admin").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("<h1>Admin Dashboard</h1>");
}
#[tokio::test]
async fn deep_directory_index() {
let proj = TestProject::new();
proj.add_page("blog/2024/index.html", "<h1>Blog 2024</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/blog/2024").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("<h1>Blog 2024</h1>");
}
#[tokio::test]
async fn dynamic_route_resolves() {
let proj = TestProject::new();
proj.add_page("post/[id].html", "<h1>Post Detail</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/post/123").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("<h1>Post Detail</h1>");
}
#[tokio::test]
async fn dynamic_route_injects_id() {
let proj = TestProject::new();
proj.add_page("post/[id].html", "<h1>Post #id#</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/post/123").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("123");
}
#[tokio::test]
async fn dynamic_route_url_encoded_param() {
let proj = TestProject::new();
proj.add_page("post/[id].html", "<p>#id#</p>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/post/hello%20world").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("hello%20world");
}
#[tokio::test]
async fn nonexistent_page_returns_404() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/nothing").await;
assert_eq!(resp.status, StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn custom_404_page() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
proj.add_page("404.html", "<h1>Oops! Not Found</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/nothing").await;
assert_eq!(resp.status, StatusCode::NOT_FOUND);
resp.assert_contains("Oops! Not Found");
}
#[tokio::test]
async fn default_404_without_custom_page() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/nothing").await;
assert_eq!(resp.status, StatusCode::NOT_FOUND);
resp.assert_contains("Page Not Found");
}
#[tokio::test]
async fn html_content_type_header() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/").await;
assert_eq!(resp.status, StatusCode::OK);
assert_eq!(resp.content_type(), Some("text/html"));
}
#[tokio::test]
async fn partial_enforces_auth_directive() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
proj.add_page(
"partials/secret.html",
"<what>\nauth: user\n</what>\n<p>TOP SECRET</p>",
);
let config = auth_config_with_secret("test-secret");
let (_dir, state) = proj.build_state_with_config(config);
let router = create_router(state);
let resp = get(&router, "/w-partial/secret").await;
assert_eq!(resp.status, StatusCode::FORBIDDEN);
resp.assert_not_contains("TOP SECRET");
}
#[tokio::test]
async fn public_partial_still_served() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
proj.add_page("partials/promo.html", "<p>Public promo</p>");
let (_dir, state) = proj.build_state();
let router = create_router(state);
let resp = get(&router, "/w-partial/promo").await;
assert_eq!(resp.status, StatusCode::OK);
resp.assert_contains("Public promo");
}
#[tokio::test]
async fn partial_inherits_application_what_auth() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
proj.add_app_config("", "auth = \"user\"\n"); proj.add_page("partials/widget.html", "<p>MEMBER WIDGET</p>"); let config = auth_config_with_secret("test-secret");
let (_dir, state) = proj.build_state_with_config(config);
let router = create_router(state);
let resp = get(&router, "/w-partial/widget").await;
assert_eq!(resp.status, StatusCode::FORBIDDEN);
resp.assert_not_contains("MEMBER WIDGET");
}
#[tokio::test]
async fn action_partial_inherits_application_what_auth() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
proj.add_app_config("", "auth = \"user\"\n");
proj.add_page("partials/widget.html", "<p>MEMBER WIDGET</p>");
let config = auth_config_with_secret("test-secret");
let (_dir, state) = proj.build_state_with_config(config);
let router = create_router(state);
let resp = post_form_with_headers(
&router,
"/w-action/notes?w-redirect=/",
"title=x&w-partial=widget",
vec![("x-requested-with", "What")],
)
.await;
resp.assert_not_contains("MEMBER WIDGET");
}
#[tokio::test]
async fn action_partial_render_enforces_auth_directive() {
let proj = TestProject::new();
proj.add_page("index.html", "<h1>Home</h1>");
proj.add_page(
"partials/secret.html",
"<what>\nauth: user\n</what>\n<p>TOP SECRET PANEL</p>",
);
let config = auth_config_with_secret("test-secret");
let (_dir, state) = proj.build_state_with_config(config);
let router = create_router(state);
let resp = post_form_with_headers(
&router,
"/w-action/notes?w-redirect=/",
"title=x&w-partial=secret",
vec![("x-requested-with", "What")],
)
.await;
resp.assert_not_contains("TOP SECRET PANEL");
}