Files
Infrastruktur-Monitoring-Sy…/backend/crates/api/tests/common/mod.rs
Dennis Nemec 83aa500f5d
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / ui (push) Has been cancelled
WP-01: domain contract and failing tests for auth and user management
Domain entities/ports, service stubs, 18 application unit tests with in-memory
fakes, API integration tests for /api/auth and /api/users, Vitest specs for the
auth store, login page and user form, Playwright auth/user-management flow.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 21:31:59 +02:00

115 lines
3.3 KiB
Rust

//! Shared helpers for API integration tests: in-memory SQLite, request helpers.
#![allow(dead_code)]
use axum::body::Body;
use axum::http::{header, Request, StatusCode};
use axum::Router;
use http_body_util::BodyExt;
use tower::ServiceExt;
pub struct Res {
pub status: StatusCode,
pub json: serde_json::Value,
pub headers: axum::http::HeaderMap,
}
pub async fn test_app() -> Router {
api::test_support::build_test_app().await
}
async fn send(app: &Router, req: Request<Body>) -> Res {
let res = app.clone().oneshot(req).await.unwrap();
let status = res.status();
let headers = res.headers().clone();
let bytes = res.into_body().collect().await.unwrap().to_bytes();
let json = serde_json::from_slice(&bytes).unwrap_or(serde_json::Value::Null);
Res {
status,
json,
headers,
}
}
fn with_auth(
mut b: axum::http::request::Builder,
token: Option<&str>,
) -> axum::http::request::Builder {
if let Some(t) = token {
b = b.header(header::AUTHORIZATION, format!("Bearer {t}"));
}
b
}
pub async fn get(app: &Router, path: &str, token: Option<&str>) -> Res {
let req = with_auth(Request::get(path), token)
.body(Body::empty())
.unwrap();
send(app, req).await
}
pub async fn send_json(
app: &Router,
method: &str,
path: &str,
body: serde_json::Value,
token: Option<&str>,
) -> Res {
let req = with_auth(Request::builder().method(method).uri(path), token)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(body.to_string()))
.unwrap();
send(app, req).await
}
pub async fn post(app: &Router, path: &str, body: serde_json::Value, token: Option<&str>) -> Res {
send_json(app, "POST", path, body, token).await
}
pub async fn patch(app: &Router, path: &str, body: serde_json::Value, token: Option<&str>) -> Res {
send_json(app, "PATCH", path, body, token).await
}
/// POST with a `Cookie` header (used for refresh/logout which read the refresh cookie).
pub async fn post_with_cookie(app: &Router, path: &str, cookie: &str) -> Res {
let req = Request::post(path)
.header(header::COOKIE, cookie)
.body(Body::empty())
.unwrap();
send(app, req).await
}
/// Extract `name=value` of a Set-Cookie header.
pub fn cookie_value(res: &Res, name: &str) -> Option<String> {
res.headers
.get_all(header::SET_COOKIE)
.iter()
.filter_map(|v| v.to_str().ok())
.find(|c| c.starts_with(&format!("{name}=")))
.map(|c| c.split(';').next().unwrap().to_string())
}
/// App with a bootstrapped admin `admin@example.com` / `admin-password-123`.
pub async fn test_app_with_admin() -> Router {
api::test_support::build_test_app_with_admin("admin@example.com", "admin-password-123").await
}
pub struct Login {
pub access: String,
pub user_id: String,
}
pub async fn login(app: &Router, email: &str, password: &str) -> Login {
let res = post(
app,
"/api/auth/login",
serde_json::json!({"email": email, "password": password}),
None,
)
.await;
assert_eq!(res.status, StatusCode::OK, "login failed: {}", res.json);
Login {
access: res.json["access_token"].as_str().unwrap().to_string(),
user_id: res.json["user"]["id"].as_str().unwrap().to_string(),
}
}