tide_testing/lib.rs
1#![forbid(unsafe_code, future_incompatible)]
2#![deny(
3 missing_debug_implementations,
4 nonstandard_style,
5 missing_copy_implementations,
6 unused_qualifications
7)]
8//! # Tide Testing Extension Trait
9//!
10//! This trait provides an ergonomic extension for testing tide applications.
11//!
12//! ## Usage:
13//!
14//! `$ cargo add -D tide-testing`
15//!
16//! ## Examples
17//!
18//! ```rust
19//! # fn main() -> tide::Result<()> { async_std::task::block_on(async {
20//! let mut app = tide::new();
21//! app.at("/").get(|_| async { Ok("hello!") });
22//!
23//! use tide_testing::TideTestingExt;
24//! assert_eq!(app.get("/").recv_string().await?, "hello!");
25//! assert_eq!(
26//! app.post("/missing").await?.status(),
27//! tide::http::StatusCode::NotFound
28//! );
29//! # Ok(()) }) }
30//! ```
31//!
32//! Note that the http methods return [`surf::RequestBuilder`]s, allowing tests to build up complex requests fluently:
33//!
34//! ```rust
35//! # fn main() -> tide::Result<()> { async_std::task::block_on(async {
36//! use tide::prelude::*;
37//! let mut app = tide::new();
38//! app.at("/complex_example")
39//! .put(|mut request: tide::Request<()>| async move {
40//! Ok(json!({
41//! "content_type": request.content_type().map(|c| c.to_string()),
42//! "body": request.body_string().await?,
43//! "header": request.header("custom").map(|h| h.as_str())
44//! }))
45//! });
46//!
47//! use tide_testing::TideTestingExt;
48//!
49//! let response_body: serde_json::value::Value = app
50//! .put("/complex_example")
51//! .body(tide::Body::from_string("hello".into()))
52//! .content_type("application/custom")
53//! .header("custom", "header-value")
54//! .recv_json()
55//! .await?;
56//!
57//! assert_eq!(
58//! response_body,
59//! json!({
60//! "content_type": Some("application/custom"),
61//! "body": "hello",
62//! "header": Some("header-value")
63//! })
64//! );
65//! # Ok(()) }) }
66//! ```
67
68pub use surf;
69use surf::http::Url;
70use surf::Client;
71use tide::Server;
72
73macro_rules! method {
74 ($method:ident) => {
75 fn $method(&self, url: impl AsRef<str>) -> surf::RequestBuilder {
76 self.client().$method(url.as_ref())
77 }
78 };
79}
80
81macro_rules! methods {
82 ($($method:ident),* $(,)?) => {$(method!($method);)+}
83}
84
85pub trait TideTestingExt {
86 fn client(&self) -> Client;
87 methods!(get, put, post, delete, head, connect, options, trace, patch);
88}
89
90impl<State: Unpin + Clone + Send + Sync + 'static> TideTestingExt for Server<State> {
91 fn client(&self) -> Client {
92 let mut client = Client::with_http_client(self.clone());
93 client.set_base_url(Url::parse("http://example.com/").unwrap());
94 client
95 }
96}