///|
/// A test HTTP client that dispatches requests directly without network I/O.
pub struct TestClient {
priv app : Mocket
fn new(app : Mocket) -> TestClient
}
///|
/// The response from a `TestClient` request, containing status, headers, and body.
pub struct TestResponse {
status : StatusCode
headers : Map[String, String]
body_bytes : Bytes
}
///|
/// Creates a new test client wrapping the given app.
pub fn TestClient::new(app : Mocket) -> TestClient {
{ app, }
}
///|
/// Returns the response body decoded as a UTF-8 string.
pub fn TestResponse::body_text(self : TestResponse) -> String {
@utf8.decode(self.body_bytes) catch {
_ => ""
}
}
///|
/// Parses the response body as JSON into a typed value.
pub fn[T : @json.FromJson] TestResponse::body_json(
self : TestResponse,
) -> T raise {
let text = @utf8.decode(self.body_bytes)
let json = @json.parse(text)
@json.from_json(json)
}
///|
/// Sends a synthetic GET request to the given path.
pub async fn TestClient::get(
self : TestClient,
path : String,
headers? : Map[String, String],
) -> TestResponse {
self.request("GET", path, headers=headers.unwrap_or({}), body=b"")
}
///|
/// Sends a synthetic POST request with optional body.
pub async fn TestClient::post(
self : TestClient,
path : String,
body? : Bytes,
headers? : Map[String, String],
) -> TestResponse {
self.request(
"POST",
path,
headers=headers.unwrap_or({}),
body=body.unwrap_or(b""),
)
}
///|
/// Sends a synthetic PUT request with optional body.
pub async fn TestClient::put(
self : TestClient,
path : String,
body? : Bytes,
headers? : Map[String, String],
) -> TestResponse {
self.request(
"PUT",
path,
headers=headers.unwrap_or({}),
body=body.unwrap_or(b""),
)
}
///|
/// Sends a synthetic DELETE request.
pub async fn TestClient::delete(
self : TestClient,
path : String,
headers? : Map[String, String],
) -> TestResponse {
self.request("DELETE", path, headers=headers.unwrap_or({}), body=b"")
}
///|
/// Dispatches a synthetic request through the full routing and middleware pipeline.
pub async fn TestClient::request(
self : TestClient,
meth : String,
path : String,
headers~ : Map[String, String],
body~ : Bytes,
) -> TestResponse {
let (status, resp_headers, body_bytes) = self.app.dispatch(
meth, path, headers, body,
)
{ status, headers: resp_headers, body_bytes }
}