1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! In-process test client for Volter applications.
//!
//! [`TestClient`] wraps a [`Router`](volter_router::Router) and drives it
//! directly in memory — no real TCP socket is bound, so tests are fast and
//! don't fight over ports in CI.
//!
//! # Quick start
//!
//! ```rust
//! use volter_testing::TestClient;
//! use volter_router::{Router, get};
//!
//! async fn handler() -> &'static str { "ok" }
//!
//! # #[tokio::main(flavor = "current_thread")]
//! # async fn main() {
//! let client = TestClient::new(Router::new().route("/", get(handler)));
//!
//! let response = client.get("/").send().await;
//! assert_eq!(response.status(), 200);
//!
//! let body = response.text().await.unwrap();
//! assert_eq!(body, "ok");
//! # }
//! ```
//!
//! # JSON round-trip
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use volter_testing::TestClient;
//! use volter_router::{Router, post};
//! use volter_extract::Json;
//!
//! #[derive(Serialize, Deserialize, PartialEq, Debug)]
//! struct Payload { name: String }
//!
//! async fn echo(Json(p): Json<Payload>) -> Json<Payload> { Json(p) }
//!
//! # #[tokio::main(flavor = "current_thread")]
//! # async fn main() {
//! let client = TestClient::new(Router::new().route("/echo", post(echo)));
//!
//! let response = client
//! .post("/echo")
//! .json(&Payload { name: "ferris".into() })
//! .send()
//! .await;
//!
//! let body: Payload = response.json().await.unwrap();
//! assert_eq!(body, Payload { name: "ferris".into() });
//! # }
//! ```
//!
//! See `ARCHITECTURE.md` → "Testing architecture" for the full design.
pub use TestRequestBuilder;
pub use ;
use Method;
use Router;
/// An in-process test client for Volter applications.
///
/// Wraps a [`Router`] and provides ergonomic helpers for issuing requests
/// and inspecting responses without binding a real TCP socket.
///
/// The type parameter `S` corresponds to the router's application state.
/// Most tests use a stateless router (`Router::new()`) which gives
/// `TestClient::new(router)` a `TestClient<()>`.
///
/// Each call to `get` / `post` / `request` clones the router (a cheap
/// `Arc` bump) so the client does not require `&mut` access.
///
/// # Example
///
/// ```rust
/// use volter_testing::TestClient;
/// use volter_router::{Router, get};
///
/// async fn handler() -> &'static str { "hello" }
///
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() {
/// let client = TestClient::new(Router::new().route("/", get(handler)));
/// let resp = client.get("/").send().await;
/// assert_eq!(resp.status(), 200);
/// # }
/// ```