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}