1use crate::internals::format_status_code_range;
2use crate::internals::DebugResponseBody;
3use crate::internals::RequestPathFormatter;
4use crate::internals::StatusCodeFormatter;
5use crate::internals::TryIntoRangeBounds;
6use anyhow::Context;
7use bytes::Bytes;
8use cookie::Cookie;
9use cookie::CookieJar;
10use http::header::HeaderName;
11use http::header::SET_COOKIE;
12use http::response::Parts;
13use http::HeaderMap;
14use http::HeaderValue;
15use http::Method;
16use http::StatusCode;
17use serde::de::DeserializeOwned;
18use serde::Serialize;
19use serde_json::Value;
20use std::convert::AsRef;
21use std::fmt::Debug;
22use std::fmt::Display;
23use std::fs::read_to_string;
24use std::fs::File;
25use std::io::BufReader;
26use std::ops::RangeBounds;
27use std::path::Path;
28use url::Url;
29
30#[cfg(feature = "pretty-assertions")]
31use pretty_assertions::{assert_eq, assert_ne};
32
33#[cfg(feature = "ws")]
34use crate::internals::TestResponseWebSocket;
35#[cfg(feature = "ws")]
36use crate::TestWebSocket;
37
38#[cfg(not(feature = "old-json-diff"))]
39use expect_json::expect;
40#[cfg(not(feature = "old-json-diff"))]
41use expect_json::expect_json_eq;
42
43#[derive(Debug, Clone)]
140pub struct TestResponse {
141 method: Method,
142
143 full_request_url: Url,
145 headers: HeaderMap<HeaderValue>,
146 status_code: StatusCode,
147 response_body: Bytes,
148
149 #[cfg(feature = "ws")]
150 websockets: TestResponseWebSocket,
151}
152
153impl TestResponse {
154 pub(crate) fn new(
155 method: Method,
156 full_request_url: Url,
157 parts: Parts,
158 response_body: Bytes,
159
160 #[cfg(feature = "ws")] websockets: TestResponseWebSocket,
161 ) -> Self {
162 Self {
163 method,
164 full_request_url,
165 headers: parts.headers,
166 status_code: parts.status,
167 response_body,
168
169 #[cfg(feature = "ws")]
170 websockets,
171 }
172 }
173
174 #[must_use]
208 pub fn text(&self) -> String {
209 String::from_utf8_lossy(self.as_bytes()).to_string()
210 }
211
212 #[must_use]
254 pub fn json<T>(&self) -> T
255 where
256 T: DeserializeOwned,
257 {
258 serde_json::from_slice::<T>(self.as_bytes())
259 .with_context(|| {
260 let debug_request_format = self.debug_request_format();
261
262 format!("Deserializing response from Json, for request {debug_request_format}")
263 })
264 .unwrap()
265 }
266
267 #[cfg(feature = "yaml")]
308 #[must_use]
309 pub fn yaml<T>(&self) -> T
310 where
311 T: DeserializeOwned,
312 {
313 serde_yaml::from_slice::<T>(self.as_bytes())
314 .with_context(|| {
315 let debug_request_format = self.debug_request_format();
316
317 format!("Deserializing response from YAML, for request {debug_request_format}")
318 })
319 .unwrap()
320 }
321
322 #[cfg(feature = "msgpack")]
363 #[must_use]
364 pub fn msgpack<T>(&self) -> T
365 where
366 T: DeserializeOwned,
367 {
368 rmp_serde::from_slice::<T>(self.as_bytes())
369 .with_context(|| {
370 let debug_request_format = self.debug_request_format();
371
372 format!("Deserializing response from MsgPack, for request {debug_request_format}")
373 })
374 .unwrap()
375 }
376
377 #[must_use]
418 pub fn form<T>(&self) -> T
419 where
420 T: DeserializeOwned,
421 {
422 serde_urlencoded::from_bytes::<T>(self.as_bytes())
423 .with_context(|| {
424 let debug_request_format = self.debug_request_format();
425
426 format!("Deserializing response from Form, for request {debug_request_format}")
427 })
428 .unwrap()
429 }
430
431 #[must_use]
433 pub fn as_bytes(&self) -> &Bytes {
434 &self.response_body
435 }
436
437 #[must_use]
440 pub fn into_bytes(self) -> Bytes {
441 self.response_body
442 }
443
444 #[must_use]
446 pub fn status_code(&self) -> StatusCode {
447 self.status_code
448 }
449
450 #[must_use]
452 pub fn request_method(&self) -> Method {
453 self.method.clone()
454 }
455
456 #[must_use]
458 pub fn request_url(&self) -> Url {
459 self.full_request_url.clone()
460 }
461
462 #[must_use]
468 pub fn maybe_header<N>(&self, name: N) -> Option<HeaderValue>
469 where
470 N: TryInto<HeaderName>,
471 N::Error: Debug,
472 {
473 let header_name = name
474 .try_into()
475 .expect("Failed to build HeaderName from name given");
476 self.headers.get(header_name).map(|h| h.to_owned())
477 }
478
479 #[must_use]
481 pub fn headers(&self) -> &HeaderMap<HeaderValue> {
482 &self.headers
483 }
484
485 #[must_use]
486 pub fn maybe_content_type(&self) -> Option<String> {
487 self.headers.get(http::header::CONTENT_TYPE).map(|header| {
488 header
489 .to_str()
490 .with_context(|| {
491 format!("Failed to decode header CONTENT_TYPE, received '{header:?}'")
492 })
493 .unwrap()
494 .to_string()
495 })
496 }
497
498 #[must_use]
499 pub fn content_type(&self) -> String {
500 self.maybe_content_type()
501 .expect("CONTENT_TYPE not found in response header")
502 }
503
504 #[must_use]
510 pub fn header<N>(&self, name: N) -> HeaderValue
511 where
512 N: TryInto<HeaderName> + Display + Clone,
513 N::Error: Debug,
514 {
515 let debug_header = name.clone();
516 let header_name = name
517 .try_into()
518 .expect("Failed to build HeaderName from name given, '{debug_header}'");
519 self.headers
520 .get(header_name)
521 .map(|h| h.to_owned())
522 .with_context(|| {
523 let debug_request_format = self.debug_request_format();
524
525 format!("Cannot find header {debug_header}, for request {debug_request_format}",)
526 })
527 .unwrap()
528 }
529
530 pub fn iter_headers(&self) -> impl Iterator<Item = (&'_ HeaderName, &'_ HeaderValue)> {
532 self.headers.iter()
533 }
534
535 pub fn iter_headers_by_name<N>(&self, name: N) -> impl Iterator<Item = &'_ HeaderValue>
537 where
538 N: TryInto<HeaderName>,
539 N::Error: Debug,
540 {
541 let header_name = name
542 .try_into()
543 .expect("Failed to build HeaderName from name given");
544 self.headers.get_all(header_name).iter()
545 }
546
547 #[must_use]
548 pub fn contains_header<N>(&self, name: N) -> bool
549 where
550 N: TryInto<HeaderName>,
551 N::Error: Debug,
552 {
553 let header_name = name
554 .try_into()
555 .expect("Failed to build HeaderName from name given");
556 self.headers.contains_key(header_name)
557 }
558
559 #[track_caller]
563 pub fn assert_contains_header<N>(&self, name: N)
564 where
565 N: TryInto<HeaderName> + Display + Clone,
566 N::Error: Debug,
567 {
568 let debug_header_name = name.clone();
569 let debug_request_format = self.debug_request_format();
570 let has_header = self.contains_header(name);
571
572 assert!(has_header, "Expected header '{debug_header_name}' to be present in response, header was not found, for request {debug_request_format}");
573 }
574
575 #[track_caller]
576 pub fn assert_header<N, V>(&self, name: N, value: V)
577 where
578 N: TryInto<HeaderName> + Display + Clone,
579 N::Error: Debug,
580 V: TryInto<HeaderValue>,
581 V::Error: Debug,
582 {
583 let debug_header_name = name.clone();
584 let header_name = name
585 .try_into()
586 .expect("Failed to build HeaderName from name given");
587 let expected_header_value = value
588 .try_into()
589 .expect("Could not turn given value into HeaderValue");
590 let debug_request_format = self.debug_request_format();
591 let maybe_found_header_value = self.maybe_header(header_name);
592
593 match maybe_found_header_value {
594 None => {
595 panic!("Expected header '{debug_header_name}' to be present in response, header was not found, for request {debug_request_format}")
596 }
597 Some(found_header_value) => {
598 assert_eq!(expected_header_value, found_header_value,)
599 }
600 }
601 }
602
603 #[must_use]
609 pub fn maybe_cookie(&self, cookie_name: &str) -> Option<Cookie<'static>> {
610 for cookie in self.iter_cookies() {
611 if cookie.name() == cookie_name {
612 return Some(cookie.into_owned());
613 }
614 }
615
616 None
617 }
618
619 #[must_use]
625 pub fn cookie(&self, cookie_name: &str) -> Cookie<'static> {
626 self.maybe_cookie(cookie_name)
627 .with_context(|| {
628 let debug_request_format = self.debug_request_format();
629
630 format!("Cannot find cookie {cookie_name}, for request {debug_request_format}")
631 })
632 .unwrap()
633 }
634
635 #[must_use]
640 pub fn cookies(&self) -> CookieJar {
641 let mut cookies = CookieJar::new();
642
643 for cookie in self.iter_cookies() {
644 cookies.add(cookie.into_owned());
645 }
646
647 cookies
648 }
649
650 pub fn iter_cookies(&self) -> impl Iterator<Item = Cookie<'_>> {
652 self.iter_headers_by_name(SET_COOKIE).map(|header| {
653 let header_str = header
654 .to_str()
655 .with_context(|| {
656 let debug_request_format = self.debug_request_format();
657
658 format!(
659 "Reading header 'Set-Cookie' as string, for request {debug_request_format}",
660 )
661 })
662 .unwrap();
663
664 Cookie::parse(header_str)
665 .with_context(|| {
666 let debug_request_format = self.debug_request_format();
667
668 format!("Parsing 'Set-Cookie' header, for request {debug_request_format}",)
669 })
670 .unwrap()
671 })
672 }
673
674 #[cfg(feature = "ws")]
706 #[must_use]
707 pub async fn into_websocket(self) -> TestWebSocket {
708 use crate::transport_layer::TransportLayerType;
709
710 if self.websockets.transport_type != TransportLayerType::Http {
712 unimplemented!("WebSocket requires a HTTP based transport layer, see `TestServerConfig::transport`");
713 }
714
715 let debug_request_format = self.debug_request_format().to_string();
716
717 let on_upgrade = self.websockets.maybe_on_upgrade.with_context(|| {
718 format!("Expected WebSocket upgrade to be found, it is None, for request {debug_request_format}")
719 })
720 .unwrap();
721
722 let upgraded = on_upgrade
723 .await
724 .with_context(|| {
725 format!("Failed to upgrade connection for, for request {debug_request_format}")
726 })
727 .unwrap();
728
729 TestWebSocket::new(upgraded).await
730 }
731
732 #[track_caller]
735 pub fn assert_text<C>(&self, expected: C)
736 where
737 C: AsRef<str>,
738 {
739 let expected_contents = expected.as_ref();
740 assert_eq!(expected_contents, &self.text());
741 }
742
743 #[track_caller]
745 pub fn assert_text_contains<C>(&self, expected: C)
746 where
747 C: AsRef<str>,
748 {
749 let expected_contents = expected.as_ref();
750 let received = self.text();
751 let is_contained = received.contains(expected_contents);
752
753 assert!(
754 is_contained,
755 "Failed to find '{expected_contents}', received '{received}'"
756 );
757 }
758
759 #[track_caller]
761 pub fn assert_text_from_file<P>(&self, path: P)
762 where
763 P: AsRef<Path>,
764 {
765 let path_ref = path.as_ref();
766 let expected = read_to_string(path_ref)
767 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
768 .unwrap();
769
770 self.assert_text(expected);
771 }
772
773 #[track_caller]
822 pub fn assert_json<T>(&self, expected: &T)
823 where
824 T: Serialize + DeserializeOwned + PartialEq<T> + Debug,
825 {
826 #[cfg(feature = "old-json-diff")]
827 {
828 assert_eq!(*expected, self.json::<T>());
829 }
830
831 #[cfg(not(feature = "old-json-diff"))]
832 {
833 let received = self.json::<T>();
834 if *expected != received {
835 if let Err(error) = expect_json_eq(&received, &expected) {
836 panic!(
837 "
838{error}
839",
840 );
841 }
842 }
843 }
844 }
845
846 #[track_caller]
884 pub fn assert_json_contains<T>(&self, expected: &T)
885 where
886 T: Serialize,
887 {
888 let received = self.json::<Value>();
889
890 #[cfg(feature = "old-json-diff")]
891 {
892 assert_json_diff::assert_json_include!(actual: received, expected: expected);
893 }
894
895 #[cfg(not(feature = "old-json-diff"))]
896 {
897 let expected_value = serde_json::to_value(expected).unwrap();
898 let result = expect_json_eq(
899 &received,
900 &expect::object().propagated_contains(expected_value),
901 );
902 if let Err(error) = result {
903 panic!(
904 "
905{error}
906",
907 );
908 }
909 }
910 }
911
912 #[track_caller]
941 pub fn assert_json_from_file<P>(&self, path: P)
942 where
943 P: AsRef<Path>,
944 {
945 let path_ref = path.as_ref();
946 let file = File::open(path_ref)
947 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
948 .unwrap();
949
950 let reader = BufReader::new(file);
951 let expected = serde_json::from_reader::<_, serde_json::Value>(reader)
952 .with_context(|| {
953 format!(
954 "Failed to deserialize file '{}' as json",
955 path_ref.display()
956 )
957 })
958 .unwrap();
959
960 self.assert_json(&expected);
961 }
962
963 #[cfg(feature = "yaml")]
969 #[track_caller]
970 pub fn assert_yaml<T>(&self, other: &T)
971 where
972 T: DeserializeOwned + PartialEq<T> + Debug,
973 {
974 assert_eq!(*other, self.yaml::<T>());
975 }
976
977 #[cfg(feature = "yaml")]
979 #[track_caller]
980 pub fn assert_yaml_from_file<P>(&self, path: P)
981 where
982 P: AsRef<Path>,
983 {
984 let path_ref = path.as_ref();
985 let file = File::open(path_ref)
986 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
987 .unwrap();
988
989 let reader = BufReader::new(file);
990 let expected = serde_yaml::from_reader::<_, serde_yaml::Value>(reader)
991 .with_context(|| {
992 format!(
993 "Failed to deserialize file '{}' as yaml",
994 path_ref.display()
995 )
996 })
997 .unwrap();
998
999 self.assert_yaml(&expected);
1000 }
1001
1002 #[cfg(feature = "msgpack")]
1008 #[track_caller]
1009 pub fn assert_msgpack<T>(&self, other: &T)
1010 where
1011 T: DeserializeOwned + PartialEq<T> + Debug,
1012 {
1013 assert_eq!(*other, self.msgpack::<T>());
1014 }
1015
1016 #[track_caller]
1022 pub fn assert_form<T>(&self, other: &T)
1023 where
1024 T: DeserializeOwned + PartialEq<T> + Debug,
1025 {
1026 assert_eq!(*other, self.form::<T>());
1027 }
1028
1029 #[track_caller]
1031 pub fn assert_status(&self, expected_status_code: StatusCode) {
1032 let received_debug = StatusCodeFormatter(self.status_code);
1033 let expected_debug = StatusCodeFormatter(expected_status_code);
1034 let debug_request_format = self.debug_request_format();
1035 let debug_body = DebugResponseBody(self);
1036
1037 assert_eq!(
1038 expected_status_code, self.status_code,
1039 "Expected status code to be {expected_debug}, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1040 );
1041 }
1042
1043 #[track_caller]
1045 pub fn assert_not_status(&self, expected_status_code: StatusCode) {
1046 let received_debug = StatusCodeFormatter(self.status_code);
1047 let expected_debug = StatusCodeFormatter(expected_status_code);
1048 let debug_request_format = self.debug_request_format();
1049 let debug_body = DebugResponseBody(self);
1050
1051 assert_ne!(
1052 expected_status_code,
1053 self.status_code,
1054 "Expected status code to not be {expected_debug}, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1055 );
1056 }
1057
1058 #[track_caller]
1061 pub fn assert_status_success(&self) {
1062 let status_code = self.status_code.as_u16();
1063 let received_debug = StatusCodeFormatter(self.status_code);
1064 let debug_request_format = self.debug_request_format();
1065 let debug_body = DebugResponseBody(self);
1066
1067 assert!(
1068 200 <= status_code && status_code <= 299,
1069 "Expect status code within 2xx range, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1070 );
1071 }
1072
1073 #[track_caller]
1076 pub fn assert_status_failure(&self) {
1077 let status_code = self.status_code.as_u16();
1078 let received_debug = StatusCodeFormatter(self.status_code);
1079 let debug_request_format = self.debug_request_format();
1080 let debug_body = DebugResponseBody(self);
1081
1082 assert!(
1083 status_code < 200 || 299 < status_code,
1084 "Expect status code outside 2xx range, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1085 );
1086 }
1087
1088 pub fn assert_status_in_range<R, S>(&self, expected_status_range: R)
1126 where
1127 R: RangeBounds<S> + TryIntoRangeBounds<StatusCode> + Debug,
1128 S: TryInto<StatusCode>,
1129 {
1130 let range = TryIntoRangeBounds::<StatusCode>::try_into_range_bounds(expected_status_range)
1131 .expect("Failed to convert status code");
1132
1133 let status_code = self.status_code();
1134 let is_in_range = range.contains(&status_code);
1135 let debug_request_format = self.debug_request_format();
1136 let debug_body = DebugResponseBody(self);
1137
1138 assert!(
1139 is_in_range,
1140 "Expected status to be in range {}, received {status_code}, for request {debug_request_format}, with body {debug_body}",
1141 format_status_code_range(range)
1142 );
1143 }
1144
1145 pub fn assert_status_not_in_range<R, S>(&self, expected_status_range: R)
1183 where
1184 R: RangeBounds<S> + TryIntoRangeBounds<StatusCode> + Debug,
1185 S: TryInto<StatusCode>,
1186 {
1187 let range = TryIntoRangeBounds::<StatusCode>::try_into_range_bounds(expected_status_range)
1188 .expect("Failed to convert status code");
1189
1190 let status_code = self.status_code();
1191 let is_not_in_range = !range.contains(&status_code);
1192 let debug_request_format = self.debug_request_format();
1193 let debug_body = DebugResponseBody(self);
1194
1195 assert!(
1196 is_not_in_range,
1197 "Expected status is not in range {}, received {status_code}, for request {debug_request_format}, with body {debug_body}",
1198 format_status_code_range(range)
1199 );
1200 }
1201
1202 #[track_caller]
1204 pub fn assert_status_ok(&self) {
1205 self.assert_status(StatusCode::OK)
1206 }
1207
1208 #[track_caller]
1210 pub fn assert_status_not_ok(&self) {
1211 self.assert_not_status(StatusCode::OK)
1212 }
1213
1214 #[track_caller]
1216 pub fn assert_status_see_other(&self) {
1217 self.assert_status(StatusCode::SEE_OTHER)
1218 }
1219
1220 #[track_caller]
1222 pub fn assert_status_bad_request(&self) {
1223 self.assert_status(StatusCode::BAD_REQUEST)
1224 }
1225
1226 #[track_caller]
1228 pub fn assert_status_not_found(&self) {
1229 self.assert_status(StatusCode::NOT_FOUND)
1230 }
1231
1232 #[track_caller]
1234 pub fn assert_status_unauthorized(&self) {
1235 self.assert_status(StatusCode::UNAUTHORIZED)
1236 }
1237
1238 #[track_caller]
1240 pub fn assert_status_forbidden(&self) {
1241 self.assert_status(StatusCode::FORBIDDEN)
1242 }
1243
1244 pub fn assert_status_conflict(&self) {
1246 self.assert_status(StatusCode::CONFLICT)
1247 }
1248
1249 #[track_caller]
1253 pub fn assert_status_payload_too_large(&self) {
1254 self.assert_status(StatusCode::PAYLOAD_TOO_LARGE)
1255 }
1256
1257 #[track_caller]
1259 pub fn assert_status_unprocessable_entity(&self) {
1260 self.assert_status(StatusCode::UNPROCESSABLE_ENTITY)
1261 }
1262
1263 #[track_caller]
1265 pub fn assert_status_too_many_requests(&self) {
1266 self.assert_status(StatusCode::TOO_MANY_REQUESTS)
1267 }
1268
1269 #[track_caller]
1274 pub fn assert_status_switching_protocols(&self) {
1275 self.assert_status(StatusCode::SWITCHING_PROTOCOLS)
1276 }
1277
1278 #[track_caller]
1280 pub fn assert_status_internal_server_error(&self) {
1281 self.assert_status(StatusCode::INTERNAL_SERVER_ERROR)
1282 }
1283
1284 #[track_caller]
1286 pub fn assert_status_service_unavailable(&self) {
1287 self.assert_status(StatusCode::SERVICE_UNAVAILABLE)
1288 }
1289
1290 fn debug_request_format(&self) -> RequestPathFormatter<'_> {
1291 RequestPathFormatter::new(&self.method, self.full_request_url.as_str(), None)
1292 }
1293}
1294
1295impl From<TestResponse> for Bytes {
1296 fn from(response: TestResponse) -> Self {
1297 response.into_bytes()
1298 }
1299}
1300
1301#[cfg(test)]
1302mod test_assert_header {
1303 use crate::TestServer;
1304 use axum::http::HeaderMap;
1305 use axum::routing::get;
1306 use axum::Router;
1307
1308 async fn route_get_header() -> HeaderMap {
1309 let mut headers = HeaderMap::new();
1310 headers.insert("x-my-custom-header", "content".parse().unwrap());
1311 headers
1312 }
1313
1314 #[tokio::test]
1315 async fn it_should_not_panic_if_contains_header_and_content_matches() {
1316 let router = Router::new().route(&"/header", get(route_get_header));
1317
1318 let server = TestServer::new(router).unwrap();
1319
1320 server
1321 .get(&"/header")
1322 .await
1323 .assert_header("x-my-custom-header", "content");
1324 }
1325
1326 #[tokio::test]
1327 #[should_panic]
1328 async fn it_should_panic_if_contains_header_and_content_does_not_match() {
1329 let router = Router::new().route(&"/header", get(route_get_header));
1330
1331 let server = TestServer::new(router).unwrap();
1332
1333 server
1334 .get(&"/header")
1335 .await
1336 .assert_header("x-my-custom-header", "different-content");
1337 }
1338
1339 #[tokio::test]
1340 #[should_panic]
1341 async fn it_should_panic_if_not_contains_header() {
1342 let router = Router::new().route(&"/header", get(route_get_header));
1343
1344 let server = TestServer::new(router).unwrap();
1345
1346 server
1347 .get(&"/header")
1348 .await
1349 .assert_header("x-custom-header-not-found", "content");
1350 }
1351}
1352
1353#[cfg(test)]
1354mod test_assert_contains_header {
1355 use crate::TestServer;
1356 use axum::http::HeaderMap;
1357 use axum::routing::get;
1358 use axum::Router;
1359
1360 async fn route_get_header() -> HeaderMap {
1361 let mut headers = HeaderMap::new();
1362 headers.insert("x-my-custom-header", "content".parse().unwrap());
1363 headers
1364 }
1365
1366 #[tokio::test]
1367 async fn it_should_not_panic_if_contains_header() {
1368 let router = Router::new().route(&"/header", get(route_get_header));
1369
1370 let server = TestServer::new(router).unwrap();
1371
1372 server
1373 .get(&"/header")
1374 .await
1375 .assert_contains_header("x-my-custom-header");
1376 }
1377
1378 #[tokio::test]
1379 #[should_panic]
1380 async fn it_should_panic_if_not_contains_header() {
1381 let router = Router::new().route(&"/header", get(route_get_header));
1382
1383 let server = TestServer::new(router).unwrap();
1384
1385 server
1386 .get(&"/header")
1387 .await
1388 .assert_contains_header("x-custom-header-not-found");
1389 }
1390}
1391
1392#[cfg(test)]
1393mod test_assert_success {
1394 use crate::TestServer;
1395 use axum::routing::get;
1396 use axum::Router;
1397 use http::StatusCode;
1398
1399 pub async fn route_get_pass() -> StatusCode {
1400 StatusCode::OK
1401 }
1402
1403 pub async fn route_get_fail() -> StatusCode {
1404 StatusCode::SERVICE_UNAVAILABLE
1405 }
1406
1407 #[tokio::test]
1408 async fn it_should_pass_when_200() {
1409 let router = Router::new()
1410 .route(&"/pass", get(route_get_pass))
1411 .route(&"/fail", get(route_get_fail));
1412
1413 let server = TestServer::new(router).unwrap();
1414
1415 let response = server.get(&"/pass").await;
1416
1417 response.assert_status_success()
1418 }
1419
1420 #[tokio::test]
1421 #[should_panic]
1422 async fn it_should_panic_when_not_200() {
1423 let router = Router::new()
1424 .route(&"/pass", get(route_get_pass))
1425 .route(&"/fail", get(route_get_fail));
1426
1427 let server = TestServer::new(router).unwrap();
1428
1429 let response = server.get(&"/fail").expect_failure().await;
1430
1431 response.assert_status_success()
1432 }
1433}
1434
1435#[cfg(test)]
1436mod test_assert_failure {
1437 use crate::TestServer;
1438 use axum::routing::get;
1439 use axum::Router;
1440 use http::StatusCode;
1441
1442 pub async fn route_get_pass() -> StatusCode {
1443 StatusCode::OK
1444 }
1445
1446 pub async fn route_get_fail() -> StatusCode {
1447 StatusCode::SERVICE_UNAVAILABLE
1448 }
1449
1450 #[tokio::test]
1451 async fn it_should_pass_when_not_200() {
1452 let router = Router::new()
1453 .route(&"/pass", get(route_get_pass))
1454 .route(&"/fail", get(route_get_fail));
1455
1456 let server = TestServer::new(router).unwrap();
1457 let response = server.get(&"/fail").expect_failure().await;
1458
1459 response.assert_status_failure()
1460 }
1461
1462 #[tokio::test]
1463 #[should_panic]
1464 async fn it_should_panic_when_200() {
1465 let router = Router::new()
1466 .route(&"/pass", get(route_get_pass))
1467 .route(&"/fail", get(route_get_fail));
1468
1469 let server = TestServer::new(router).unwrap();
1470 let response = server.get(&"/pass").await;
1471
1472 response.assert_status_failure()
1473 }
1474}
1475
1476#[cfg(test)]
1477mod test_assert_status {
1478 use crate::TestServer;
1479 use axum::routing::get;
1480 use axum::Router;
1481 use http::StatusCode;
1482
1483 pub async fn route_get_ok() -> StatusCode {
1484 StatusCode::OK
1485 }
1486
1487 #[tokio::test]
1488 async fn it_should_pass_if_given_right_status_code() {
1489 let router = Router::new().route(&"/ok", get(route_get_ok));
1490 let server = TestServer::new(router).unwrap();
1491
1492 server.get(&"/ok").await.assert_status(StatusCode::OK);
1493 }
1494
1495 #[tokio::test]
1496 #[should_panic]
1497 async fn it_should_panic_when_status_code_does_not_match() {
1498 let router = Router::new().route(&"/ok", get(route_get_ok));
1499 let server = TestServer::new(router).unwrap();
1500
1501 server.get(&"/ok").await.assert_status(StatusCode::ACCEPTED);
1502 }
1503}
1504
1505#[cfg(test)]
1506mod test_assert_not_status {
1507 use crate::TestServer;
1508 use axum::routing::get;
1509 use axum::Router;
1510 use http::StatusCode;
1511
1512 pub async fn route_get_ok() -> StatusCode {
1513 StatusCode::OK
1514 }
1515
1516 #[tokio::test]
1517 async fn it_should_pass_if_status_code_does_not_match() {
1518 let router = Router::new().route(&"/ok", get(route_get_ok));
1519 let server = TestServer::new(router).unwrap();
1520
1521 server
1522 .get(&"/ok")
1523 .await
1524 .assert_not_status(StatusCode::ACCEPTED);
1525 }
1526
1527 #[tokio::test]
1528 #[should_panic]
1529 async fn it_should_panic_if_status_code_matches() {
1530 let router = Router::new().route(&"/ok", get(route_get_ok));
1531 let server = TestServer::new(router).unwrap();
1532
1533 server.get(&"/ok").await.assert_not_status(StatusCode::OK);
1534 }
1535}
1536
1537#[cfg(test)]
1538mod test_assert_status_in_range {
1539 use crate::TestServer;
1540 use axum::routing::get;
1541 use axum::routing::Router;
1542 use http::StatusCode;
1543 use std::ops::RangeFull;
1544
1545 #[tokio::test]
1546 async fn it_should_be_true_when_within_int_range() {
1547 let app = Router::new().route(
1548 &"/status",
1549 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1550 );
1551
1552 TestServer::new(app)
1553 .unwrap()
1554 .get(&"/status")
1555 .await
1556 .assert_status_in_range(200..299);
1557 }
1558
1559 #[tokio::test]
1560 async fn it_should_be_true_when_within_status_code_range() {
1561 let app = Router::new().route(
1562 &"/status",
1563 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1564 );
1565
1566 TestServer::new(app)
1567 .unwrap()
1568 .get(&"/status")
1569 .await
1570 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1571 }
1572
1573 #[tokio::test]
1574 #[should_panic]
1575 async fn it_should_be_false_when_outside_int_range() {
1576 let app = Router::new().route(
1577 &"/status",
1578 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1579 );
1580
1581 TestServer::new(app)
1582 .unwrap()
1583 .get(&"/status")
1584 .await
1585 .assert_status_in_range(200..299);
1586 }
1587
1588 #[tokio::test]
1589 #[should_panic]
1590 async fn it_should_be_false_when_outside_status_code_range() {
1591 let app = Router::new().route(
1592 &"/status",
1593 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1594 );
1595
1596 TestServer::new(app)
1597 .unwrap()
1598 .get(&"/status")
1599 .await
1600 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1601 }
1602
1603 #[tokio::test]
1604 async fn it_should_be_true_when_within_inclusive_range() {
1605 let app = Router::new().route(
1606 &"/status",
1607 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1608 );
1609
1610 TestServer::new(app)
1611 .unwrap()
1612 .get(&"/status")
1613 .await
1614 .assert_status_in_range(200..=299);
1615 }
1616
1617 #[tokio::test]
1618 #[should_panic]
1619 async fn it_should_be_false_when_outside_inclusive_range() {
1620 let app = Router::new().route(
1621 &"/status",
1622 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1623 );
1624
1625 TestServer::new(app)
1626 .unwrap()
1627 .get(&"/status")
1628 .await
1629 .assert_status_in_range(200..=299);
1630 }
1631
1632 #[tokio::test]
1633 async fn it_should_be_true_when_within_to_range() {
1634 let app = Router::new().route(
1635 &"/status",
1636 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1637 );
1638
1639 TestServer::new(app)
1640 .unwrap()
1641 .get(&"/status")
1642 .await
1643 .assert_status_in_range(..299);
1644 }
1645
1646 #[tokio::test]
1647 #[should_panic]
1648 async fn it_should_be_false_when_outside_to_range() {
1649 let app = Router::new().route(
1650 &"/status",
1651 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1652 );
1653
1654 TestServer::new(app)
1655 .unwrap()
1656 .get(&"/status")
1657 .await
1658 .assert_status_in_range(..299);
1659 }
1660
1661 #[tokio::test]
1662 async fn it_should_be_true_when_within_to_inclusive_range() {
1663 let app = Router::new().route(
1664 &"/status",
1665 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1666 );
1667
1668 TestServer::new(app)
1669 .unwrap()
1670 .get(&"/status")
1671 .await
1672 .assert_status_in_range(..=299);
1673 }
1674
1675 #[tokio::test]
1676 #[should_panic]
1677 async fn it_should_be_false_when_outside_to_inclusive_range() {
1678 let app = Router::new().route(
1679 &"/status",
1680 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1681 );
1682
1683 TestServer::new(app)
1684 .unwrap()
1685 .get(&"/status")
1686 .await
1687 .assert_status_in_range(..=299);
1688 }
1689
1690 #[tokio::test]
1691 async fn it_should_be_true_when_within_from_range() {
1692 let app = Router::new().route(
1693 &"/status",
1694 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1695 );
1696
1697 TestServer::new(app)
1698 .unwrap()
1699 .get(&"/status")
1700 .await
1701 .assert_status_in_range(200..);
1702 }
1703
1704 #[tokio::test]
1705 #[should_panic]
1706 async fn it_should_be_false_when_outside_from_range() {
1707 let app = Router::new().route(
1708 &"/status",
1709 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1710 );
1711
1712 TestServer::new(app)
1713 .unwrap()
1714 .get(&"/status")
1715 .await
1716 .assert_status_in_range(500..);
1717 }
1718
1719 #[tokio::test]
1720 async fn it_should_be_true_for_rull_range() {
1721 let app = Router::new().route(
1722 &"/status",
1723 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1724 );
1725
1726 TestServer::new(app)
1727 .unwrap()
1728 .get(&"/status")
1729 .await
1730 .assert_status_in_range::<RangeFull, StatusCode>(..);
1731 }
1732}
1733
1734#[cfg(test)]
1735mod test_assert_status_not_in_range {
1736 use crate::TestServer;
1737 use axum::routing::get;
1738 use axum::routing::Router;
1739 use http::StatusCode;
1740 use std::ops::RangeFull;
1741
1742 #[tokio::test]
1743 #[should_panic]
1744 async fn it_should_be_false_when_within_int_range() {
1745 let app = Router::new().route(
1746 &"/status",
1747 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1748 );
1749
1750 TestServer::new(app)
1751 .unwrap()
1752 .get(&"/status")
1753 .await
1754 .assert_status_not_in_range(200..299);
1755 }
1756
1757 #[tokio::test]
1758 #[should_panic]
1759 async fn it_should_be_false_when_within_status_code_range() {
1760 let app = Router::new().route(
1761 &"/status",
1762 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1763 );
1764
1765 TestServer::new(app)
1766 .unwrap()
1767 .get(&"/status")
1768 .await
1769 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1770 }
1771
1772 #[tokio::test]
1773 async fn it_should_be_true_when_outside_int_range() {
1774 let app = Router::new().route(
1775 &"/status",
1776 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1777 );
1778
1779 TestServer::new(app)
1780 .unwrap()
1781 .get(&"/status")
1782 .await
1783 .assert_status_not_in_range(200..299);
1784 }
1785
1786 #[tokio::test]
1787 async fn it_should_be_true_when_outside_status_code_range() {
1788 let app = Router::new().route(
1789 &"/status",
1790 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1791 );
1792
1793 TestServer::new(app)
1794 .unwrap()
1795 .get(&"/status")
1796 .await
1797 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1798 }
1799
1800 #[tokio::test]
1801 #[should_panic]
1802 async fn it_should_be_false_when_within_inclusive_range() {
1803 let app = Router::new().route(
1804 &"/status",
1805 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1806 );
1807
1808 TestServer::new(app)
1809 .unwrap()
1810 .get(&"/status")
1811 .await
1812 .assert_status_not_in_range(200..=299);
1813 }
1814
1815 #[tokio::test]
1816 async fn it_should_be_true_when_outside_inclusive_range() {
1817 let app = Router::new().route(
1818 &"/status",
1819 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1820 );
1821
1822 TestServer::new(app)
1823 .unwrap()
1824 .get(&"/status")
1825 .await
1826 .assert_status_not_in_range(200..=299);
1827 }
1828
1829 #[tokio::test]
1830 #[should_panic]
1831 async fn it_should_be_false_when_within_to_range() {
1832 let app = Router::new().route(
1833 &"/status",
1834 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1835 );
1836
1837 TestServer::new(app)
1838 .unwrap()
1839 .get(&"/status")
1840 .await
1841 .assert_status_not_in_range(..299);
1842 }
1843
1844 #[tokio::test]
1845 async fn it_should_be_true_when_outside_to_range() {
1846 let app = Router::new().route(
1847 &"/status",
1848 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1849 );
1850
1851 TestServer::new(app)
1852 .unwrap()
1853 .get(&"/status")
1854 .await
1855 .assert_status_not_in_range(..299);
1856 }
1857
1858 #[tokio::test]
1859 #[should_panic]
1860 async fn it_should_be_false_when_within_to_inclusive_range() {
1861 let app = Router::new().route(
1862 &"/status",
1863 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1864 );
1865
1866 TestServer::new(app)
1867 .unwrap()
1868 .get(&"/status")
1869 .await
1870 .assert_status_not_in_range(..=299);
1871 }
1872
1873 #[tokio::test]
1874 async fn it_should_be_true_when_outside_to_inclusive_range() {
1875 let app = Router::new().route(
1876 &"/status",
1877 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1878 );
1879
1880 TestServer::new(app)
1881 .unwrap()
1882 .get(&"/status")
1883 .await
1884 .assert_status_not_in_range(..=299);
1885 }
1886
1887 #[tokio::test]
1888 #[should_panic]
1889 async fn it_should_be_false_when_within_from_range() {
1890 let app = Router::new().route(
1891 &"/status",
1892 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1893 );
1894
1895 TestServer::new(app)
1896 .unwrap()
1897 .get(&"/status")
1898 .await
1899 .assert_status_not_in_range(200..);
1900 }
1901
1902 #[tokio::test]
1903 async fn it_should_be_true_when_outside_from_range() {
1904 let app = Router::new().route(
1905 &"/status",
1906 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1907 );
1908
1909 TestServer::new(app)
1910 .unwrap()
1911 .get(&"/status")
1912 .await
1913 .assert_status_not_in_range(500..);
1914 }
1915
1916 #[tokio::test]
1917 #[should_panic]
1918 async fn it_should_be_false_for_rull_range() {
1919 let app = Router::new().route(
1920 &"/status",
1921 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1922 );
1923
1924 TestServer::new(app)
1925 .unwrap()
1926 .get(&"/status")
1927 .await
1928 .assert_status_not_in_range::<RangeFull, StatusCode>(..);
1929 }
1930}
1931
1932#[cfg(test)]
1933mod test_into_bytes {
1934 use crate::TestServer;
1935 use axum::routing::get;
1936 use axum::Json;
1937 use axum::Router;
1938 use serde_json::json;
1939 use serde_json::Value;
1940
1941 async fn route_get_json() -> Json<Value> {
1942 Json(json!({
1943 "message": "it works?"
1944 }))
1945 }
1946
1947 #[tokio::test]
1948 async fn it_should_deserialize_into_json() {
1949 let app = Router::new().route(&"/json", get(route_get_json));
1950
1951 let server = TestServer::new(app).unwrap();
1952
1953 let bytes = server.get(&"/json").await.into_bytes();
1954 let text = String::from_utf8_lossy(&bytes);
1955
1956 assert_eq!(text, r#"{"message":"it works?"}"#);
1957 }
1958}
1959
1960#[cfg(test)]
1961mod test_content_type {
1962 use crate::TestServer;
1963 use axum::routing::get;
1964 use axum::Json;
1965 use axum::Router;
1966 use serde::Deserialize;
1967 use serde::Serialize;
1968
1969 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1970 struct ExampleResponse {
1971 name: String,
1972 age: u32,
1973 }
1974
1975 #[tokio::test]
1976 async fn it_should_retrieve_json_content_type_for_json() {
1977 let app = Router::new().route(
1978 &"/json",
1979 get(|| async {
1980 Json(ExampleResponse {
1981 name: "Joe".to_string(),
1982 age: 20,
1983 })
1984 }),
1985 );
1986
1987 let server = TestServer::new(app).unwrap();
1988
1989 let content_type = server.get(&"/json").await.content_type();
1990 assert_eq!(content_type, "application/json");
1991 }
1992
1993 #[cfg(feature = "yaml")]
1994 #[tokio::test]
1995 async fn it_should_retrieve_yaml_content_type_for_yaml() {
1996 use axum_yaml::Yaml;
1997
1998 let app = Router::new().route(
1999 &"/yaml",
2000 get(|| async {
2001 Yaml(ExampleResponse {
2002 name: "Joe".to_string(),
2003 age: 20,
2004 })
2005 }),
2006 );
2007
2008 let server = TestServer::new(app).unwrap();
2009
2010 let content_type = server.get(&"/yaml").await.content_type();
2011 assert_eq!(content_type, "application/yaml");
2012 }
2013}
2014
2015#[cfg(test)]
2016mod test_json {
2017 use crate::TestServer;
2018 use axum::routing::get;
2019 use axum::Json;
2020 use axum::Router;
2021 use serde::Deserialize;
2022 use serde::Serialize;
2023
2024 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2025 struct ExampleResponse {
2026 name: String,
2027 age: u32,
2028 }
2029
2030 async fn route_get_json() -> Json<ExampleResponse> {
2031 Json(ExampleResponse {
2032 name: "Joe".to_string(),
2033 age: 20,
2034 })
2035 }
2036
2037 #[tokio::test]
2038 async fn it_should_deserialize_into_json() {
2039 let app = Router::new().route(&"/json", get(route_get_json));
2040
2041 let server = TestServer::new(app).unwrap();
2042
2043 let response = server.get(&"/json").await.json::<ExampleResponse>();
2044
2045 assert_eq!(
2046 response,
2047 ExampleResponse {
2048 name: "Joe".to_string(),
2049 age: 20,
2050 }
2051 );
2052 }
2053}
2054
2055#[cfg(feature = "yaml")]
2056#[cfg(test)]
2057mod test_yaml {
2058 use crate::TestServer;
2059 use axum::routing::get;
2060 use axum::Router;
2061 use axum_yaml::Yaml;
2062 use serde::Deserialize;
2063 use serde::Serialize;
2064
2065 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2066 struct ExampleResponse {
2067 name: String,
2068 age: u32,
2069 }
2070
2071 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2072 Yaml(ExampleResponse {
2073 name: "Joe".to_string(),
2074 age: 20,
2075 })
2076 }
2077
2078 #[tokio::test]
2079 async fn it_should_deserialize_into_yaml() {
2080 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2081
2082 let server = TestServer::new(app).unwrap();
2083
2084 let response = server.get(&"/yaml").await.yaml::<ExampleResponse>();
2085
2086 assert_eq!(
2087 response,
2088 ExampleResponse {
2089 name: "Joe".to_string(),
2090 age: 20,
2091 }
2092 );
2093 }
2094}
2095
2096#[cfg(feature = "msgpack")]
2097#[cfg(test)]
2098mod test_msgpack {
2099 use crate::TestServer;
2100 use axum::routing::get;
2101 use axum::Router;
2102 use axum_msgpack::MsgPack;
2103 use serde::Deserialize;
2104 use serde::Serialize;
2105
2106 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2107 struct ExampleResponse {
2108 name: String,
2109 age: u32,
2110 }
2111
2112 async fn route_get_msgpack() -> MsgPack<ExampleResponse> {
2113 MsgPack(ExampleResponse {
2114 name: "Joe".to_string(),
2115 age: 20,
2116 })
2117 }
2118
2119 #[tokio::test]
2120 async fn it_should_deserialize_into_msgpack() {
2121 let app = Router::new().route(&"/msgpack", get(route_get_msgpack));
2122
2123 let server = TestServer::new(app).unwrap();
2124
2125 let response = server.get(&"/msgpack").await.msgpack::<ExampleResponse>();
2126
2127 assert_eq!(
2128 response,
2129 ExampleResponse {
2130 name: "Joe".to_string(),
2131 age: 20,
2132 }
2133 );
2134 }
2135}
2136
2137#[cfg(test)]
2138mod test_form {
2139 use crate::TestServer;
2140 use axum::routing::get;
2141 use axum::Form;
2142 use axum::Router;
2143 use serde::Deserialize;
2144 use serde::Serialize;
2145
2146 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2147 struct ExampleResponse {
2148 name: String,
2149 age: u32,
2150 }
2151
2152 async fn route_get_form() -> Form<ExampleResponse> {
2153 Form(ExampleResponse {
2154 name: "Joe".to_string(),
2155 age: 20,
2156 })
2157 }
2158
2159 #[tokio::test]
2160 async fn it_should_deserialize_into_form() {
2161 let app = Router::new().route(&"/form", get(route_get_form));
2162
2163 let server = TestServer::new(app).unwrap();
2164
2165 let response = server.get(&"/form").await.form::<ExampleResponse>();
2166
2167 assert_eq!(
2168 response,
2169 ExampleResponse {
2170 name: "Joe".to_string(),
2171 age: 20,
2172 }
2173 );
2174 }
2175}
2176
2177#[cfg(test)]
2178mod test_from {
2179 use crate::TestServer;
2180 use axum::routing::get;
2181 use axum::Router;
2182 use bytes::Bytes;
2183
2184 #[tokio::test]
2185 async fn it_should_turn_into_response_bytes() {
2186 let app = Router::new().route(&"/text", get(|| async { "This is some example text" }));
2187 let server = TestServer::new(app).unwrap();
2188
2189 let response = server.get(&"/text").await;
2190 let bytes: Bytes = response.into();
2191 let text = String::from_utf8_lossy(&bytes);
2192 assert_eq!(text, "This is some example text");
2193 }
2194}
2195
2196#[cfg(test)]
2197mod test_assert_text {
2198 use crate::TestServer;
2199 use axum::routing::get;
2200 use axum::Router;
2201
2202 fn new_test_server() -> TestServer {
2203 async fn route_get_text() -> &'static str {
2204 "This is some example text"
2205 }
2206
2207 let app = Router::new().route(&"/text", get(route_get_text));
2208 TestServer::new(app).unwrap()
2209 }
2210
2211 #[tokio::test]
2212 async fn it_should_match_whole_text() {
2213 let server = new_test_server();
2214
2215 server
2216 .get(&"/text")
2217 .await
2218 .assert_text("This is some example text");
2219 }
2220
2221 #[tokio::test]
2222 #[should_panic]
2223 async fn it_should_not_match_partial_text() {
2224 let server = new_test_server();
2225
2226 server.get(&"/text").await.assert_text("some example");
2227 }
2228
2229 #[tokio::test]
2230 #[should_panic]
2231 async fn it_should_not_match_different_text() {
2232 let server = new_test_server();
2233
2234 server.get(&"/text").await.assert_text("🦊");
2235 }
2236}
2237
2238#[cfg(test)]
2239mod test_assert_text_contains {
2240 use crate::TestServer;
2241 use axum::routing::get;
2242 use axum::Router;
2243
2244 fn new_test_server() -> TestServer {
2245 async fn route_get_text() -> &'static str {
2246 "This is some example text"
2247 }
2248
2249 let app = Router::new().route(&"/text", get(route_get_text));
2250 TestServer::new(app).unwrap()
2251 }
2252
2253 #[tokio::test]
2254 async fn it_should_match_whole_text() {
2255 let server = new_test_server();
2256
2257 server
2258 .get(&"/text")
2259 .await
2260 .assert_text_contains("This is some example text");
2261 }
2262
2263 #[tokio::test]
2264 async fn it_should_match_partial_text() {
2265 let server = new_test_server();
2266
2267 server
2268 .get(&"/text")
2269 .await
2270 .assert_text_contains("some example");
2271 }
2272
2273 #[tokio::test]
2274 #[should_panic]
2275 async fn it_should_not_match_different_text() {
2276 let server = new_test_server();
2277
2278 server.get(&"/text").await.assert_text_contains("🦊");
2279 }
2280}
2281
2282#[cfg(test)]
2283mod test_assert_text_from_file {
2284 use crate::TestServer;
2285 use axum::routing::get;
2286 use axum::routing::Router;
2287
2288 #[tokio::test]
2289 async fn it_should_match_from_file() {
2290 let app = Router::new().route(&"/text", get(|| async { "hello!" }));
2291 let server = TestServer::new(app).unwrap();
2292
2293 server
2294 .get(&"/text")
2295 .await
2296 .assert_text_from_file("files/example.txt");
2297 }
2298
2299 #[tokio::test]
2300 #[should_panic]
2301 async fn it_should_panic_when_not_match_the_file() {
2302 let app = Router::new().route(&"/text", get(|| async { "🦊" }));
2303 let server = TestServer::new(app).unwrap();
2304
2305 server
2306 .get(&"/text")
2307 .await
2308 .assert_text_from_file("files/example.txt");
2309 }
2310}
2311
2312#[cfg(test)]
2313mod test_assert_json {
2314 use crate::expect_json::expect_core::Context;
2315 use crate::expect_json::expect_core::ExpectOp;
2316 use crate::expect_json::expect_core::ExpectOpResult;
2317 use crate::TestServer;
2318 use ::expect_json::expect_core::expect_op;
2320 use axum::routing::get;
2321 use axum::Form;
2322 use axum::Json;
2323 use axum::Router;
2324 use serde::Deserialize;
2325 use serde::Serialize;
2326 use serde_json::json;
2327
2328 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2329 struct ExampleResponse {
2330 name: String,
2331 age: u32,
2332 }
2333
2334 async fn route_get_form() -> Form<ExampleResponse> {
2335 Form(ExampleResponse {
2336 name: "Joe".to_string(),
2337 age: 20,
2338 })
2339 }
2340
2341 async fn route_get_json() -> Json<ExampleResponse> {
2342 Json(ExampleResponse {
2343 name: "Joe".to_string(),
2344 age: 20,
2345 })
2346 }
2347
2348 #[tokio::test]
2349 async fn it_should_match_json_returned() {
2350 let app = Router::new().route(&"/json", get(route_get_json));
2351
2352 let server = TestServer::new(app).unwrap();
2353
2354 server.get(&"/json").await.assert_json(&ExampleResponse {
2355 name: "Joe".to_string(),
2356 age: 20,
2357 });
2358 }
2359
2360 #[tokio::test]
2361 #[should_panic]
2362 async fn it_should_panic_if_response_is_different() {
2363 let app = Router::new().route(&"/json", get(route_get_json));
2364
2365 let server = TestServer::new(app).unwrap();
2366
2367 server.get(&"/json").await.assert_json(&ExampleResponse {
2368 name: "Julia".to_string(),
2369 age: 25,
2370 });
2371 }
2372
2373 #[tokio::test]
2374 #[should_panic]
2375 async fn it_should_panic_if_response_is_form() {
2376 let app = Router::new().route(&"/form", get(route_get_form));
2377
2378 let server = TestServer::new(app).unwrap();
2379
2380 server.get(&"/form").await.assert_json(&ExampleResponse {
2381 name: "Joe".to_string(),
2382 age: 20,
2383 });
2384 }
2385
2386 #[tokio::test]
2387 async fn it_should_work_with_custom_expect_op() {
2388 #[expect_op]
2389 #[derive(Clone, Debug)]
2390 struct ExpectStrMinLen {
2391 min: usize,
2392 }
2393
2394 impl ExpectOp for ExpectStrMinLen {
2395 fn on_string(&self, _context: &mut Context<'_>, received: &str) -> ExpectOpResult<()> {
2396 if received.len() < self.min {
2397 panic!("String is too short, received: {received}");
2398 }
2399
2400 Ok(())
2401 }
2402 }
2403
2404 let app = Router::new().route(&"/json", get(route_get_json));
2405 let server = TestServer::new(app).unwrap();
2406
2407 server.get(&"/json").await.assert_json(&json!({
2408 "name": ExpectStrMinLen { min: 3 },
2409 "age": 20,
2410 }));
2411 }
2412}
2413
2414#[cfg(test)]
2415mod test_assert_json_contains {
2416 use crate::TestServer;
2417 use axum::routing::get;
2418 use axum::Form;
2419 use axum::Json;
2420 use axum::Router;
2421 use serde::Deserialize;
2422 use serde::Serialize;
2423 use serde_json::json;
2424 use std::time::Instant;
2425
2426 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2427 struct ExampleResponse {
2428 time: u64,
2429 name: String,
2430 age: u32,
2431 }
2432
2433 async fn route_get_form() -> Form<ExampleResponse> {
2434 Form(ExampleResponse {
2435 time: Instant::now().elapsed().as_millis() as u64,
2436 name: "Joe".to_string(),
2437 age: 20,
2438 })
2439 }
2440
2441 async fn route_get_json() -> Json<ExampleResponse> {
2442 Json(ExampleResponse {
2443 time: Instant::now().elapsed().as_millis() as u64,
2444 name: "Joe".to_string(),
2445 age: 20,
2446 })
2447 }
2448
2449 #[tokio::test]
2450 async fn it_should_match_subset_of_json_returned() {
2451 let app = Router::new().route(&"/json", get(route_get_json));
2452 let server = TestServer::new(app).unwrap();
2453
2454 server.get(&"/json").await.assert_json_contains(&json!({
2455 "name": "Joe",
2456 "age": 20,
2457 }));
2458 }
2459
2460 #[tokio::test]
2461 #[should_panic]
2462 async fn it_should_panic_if_response_is_different() {
2463 let app = Router::new().route(&"/json", get(route_get_json));
2464 let server = TestServer::new(app).unwrap();
2465
2466 server
2467 .get(&"/json")
2468 .await
2469 .assert_json_contains(&ExampleResponse {
2470 time: 1234,
2471 name: "Julia".to_string(),
2472 age: 25,
2473 });
2474 }
2475
2476 #[tokio::test]
2477 #[should_panic]
2478 async fn it_should_panic_if_response_is_form() {
2479 let app = Router::new().route(&"/form", get(route_get_form));
2480 let server = TestServer::new(app).unwrap();
2481
2482 server.get(&"/form").await.assert_json_contains(&json!({
2483 "name": "Joe",
2484 "age": 20,
2485 }));
2486 }
2487
2488 #[tokio::test]
2490 async fn it_should_propagate_contains_to_sub_objects() {
2491 let json_result = json!({ "a": {"prop1": "value1"} }).to_string();
2492 let app = Router::new().route(&"/json", get(|| async { json_result }));
2493
2494 let server = TestServer::new(app).unwrap();
2495 let response = server.get("/json").await;
2496
2497 response.assert_json_contains(&json!({ "a": {} }));
2498 }
2499}
2500
2501#[cfg(test)]
2502mod test_assert_json_from_file {
2503 use crate::TestServer;
2504 use axum::routing::get;
2505 use axum::routing::Router;
2506 use axum::Form;
2507 use axum::Json;
2508 use serde::Deserialize;
2509 use serde::Serialize;
2510 use serde_json::json;
2511
2512 #[tokio::test]
2513 async fn it_should_match_json_from_file() {
2514 let app = Router::new().route(
2515 &"/json",
2516 get(|| async {
2517 Json(json!(
2518 {
2519 "name": "Joe",
2520 "age": 20,
2521 }
2522 ))
2523 }),
2524 );
2525 let server = TestServer::new(app).unwrap();
2526
2527 server
2528 .get(&"/json")
2529 .await
2530 .assert_json_from_file("files/example.json");
2531 }
2532
2533 #[tokio::test]
2534 #[should_panic]
2535 async fn it_should_panic_when_not_match_the_file() {
2536 let app = Router::new().route(
2537 &"/json",
2538 get(|| async {
2539 Json(json!(
2540 {
2541 "name": "Julia",
2542 "age": 25,
2543 }
2544 ))
2545 }),
2546 );
2547 let server = TestServer::new(app).unwrap();
2548
2549 server
2550 .get(&"/json")
2551 .await
2552 .assert_json_from_file("files/example.json");
2553 }
2554
2555 #[tokio::test]
2556 #[should_panic]
2557 async fn it_should_panic_when_content_type_does_not_match() {
2558 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2559 struct ExampleResponse {
2560 name: String,
2561 age: u32,
2562 }
2563
2564 let app = Router::new().route(
2565 &"/form",
2566 get(|| async {
2567 Form(ExampleResponse {
2568 name: "Joe".to_string(),
2569 age: 20,
2570 })
2571 }),
2572 );
2573 let server = TestServer::new(app).unwrap();
2574
2575 server
2576 .get(&"/form")
2577 .await
2578 .assert_json_from_file("files/example.json");
2579 }
2580}
2581
2582#[cfg(feature = "yaml")]
2583#[cfg(test)]
2584mod test_assert_yaml {
2585 use crate::TestServer;
2586 use axum::routing::get;
2587 use axum::Form;
2588 use axum::Router;
2589 use axum_yaml::Yaml;
2590 use serde::Deserialize;
2591 use serde::Serialize;
2592
2593 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2594 struct ExampleResponse {
2595 name: String,
2596 age: u32,
2597 }
2598
2599 async fn route_get_form() -> Form<ExampleResponse> {
2600 Form(ExampleResponse {
2601 name: "Joe".to_string(),
2602 age: 20,
2603 })
2604 }
2605
2606 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2607 Yaml(ExampleResponse {
2608 name: "Joe".to_string(),
2609 age: 20,
2610 })
2611 }
2612
2613 #[tokio::test]
2614 async fn it_should_match_yaml_returned() {
2615 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2616
2617 let server = TestServer::new(app).unwrap();
2618
2619 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2620 name: "Joe".to_string(),
2621 age: 20,
2622 });
2623 }
2624
2625 #[tokio::test]
2626 #[should_panic]
2627 async fn it_should_panic_if_response_is_different() {
2628 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2629
2630 let server = TestServer::new(app).unwrap();
2631
2632 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2633 name: "Julia".to_string(),
2634 age: 25,
2635 });
2636 }
2637
2638 #[tokio::test]
2639 #[should_panic]
2640 async fn it_should_panic_if_response_is_form() {
2641 let app = Router::new().route(&"/form", get(route_get_form));
2642
2643 let server = TestServer::new(app).unwrap();
2644
2645 server.get(&"/form").await.assert_yaml(&ExampleResponse {
2646 name: "Joe".to_string(),
2647 age: 20,
2648 });
2649 }
2650}
2651
2652#[cfg(feature = "yaml")]
2653#[cfg(test)]
2654mod test_assert_yaml_from_file {
2655 use crate::TestServer;
2656 use axum::routing::get;
2657 use axum::routing::Router;
2658 use axum::Form;
2659 use axum_yaml::Yaml;
2660 use serde::Deserialize;
2661 use serde::Serialize;
2662 use serde_json::json;
2663
2664 #[tokio::test]
2665 async fn it_should_match_yaml_from_file() {
2666 let app = Router::new().route(
2667 &"/yaml",
2668 get(|| async {
2669 Yaml(json!(
2670 {
2671 "name": "Joe",
2672 "age": 20,
2673 }
2674 ))
2675 }),
2676 );
2677 let server = TestServer::new(app).unwrap();
2678
2679 server
2680 .get(&"/yaml")
2681 .await
2682 .assert_yaml_from_file("files/example.yaml");
2683 }
2684
2685 #[tokio::test]
2686 #[should_panic]
2687 async fn it_should_panic_when_not_match_the_file() {
2688 let app = Router::new().route(
2689 &"/yaml",
2690 get(|| async {
2691 Yaml(json!(
2692 {
2693 "name": "Julia",
2694 "age": 25,
2695 }
2696 ))
2697 }),
2698 );
2699 let server = TestServer::new(app).unwrap();
2700
2701 server
2702 .get(&"/yaml")
2703 .await
2704 .assert_yaml_from_file("files/example.yaml");
2705 }
2706
2707 #[tokio::test]
2708 #[should_panic]
2709 async fn it_should_panic_when_content_type_does_not_match() {
2710 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2711 struct ExampleResponse {
2712 name: String,
2713 age: u32,
2714 }
2715
2716 let app = Router::new().route(
2717 &"/form",
2718 get(|| async {
2719 Form(ExampleResponse {
2720 name: "Joe".to_string(),
2721 age: 20,
2722 })
2723 }),
2724 );
2725 let server = TestServer::new(app).unwrap();
2726
2727 server
2728 .get(&"/form")
2729 .await
2730 .assert_yaml_from_file("files/example.yaml");
2731 }
2732}
2733
2734#[cfg(test)]
2735mod test_assert_form {
2736 use crate::TestServer;
2737 use axum::routing::get;
2738 use axum::Form;
2739 use axum::Json;
2740 use axum::Router;
2741 use serde::Deserialize;
2742 use serde::Serialize;
2743
2744 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2745 struct ExampleResponse {
2746 name: String,
2747 age: u32,
2748 }
2749
2750 async fn route_get_form() -> Form<ExampleResponse> {
2751 Form(ExampleResponse {
2752 name: "Joe".to_string(),
2753 age: 20,
2754 })
2755 }
2756
2757 async fn route_get_json() -> Json<ExampleResponse> {
2758 Json(ExampleResponse {
2759 name: "Joe".to_string(),
2760 age: 20,
2761 })
2762 }
2763
2764 #[tokio::test]
2765 async fn it_should_match_form_returned() {
2766 let app = Router::new().route(&"/form", get(route_get_form));
2767
2768 let server = TestServer::new(app).unwrap();
2769
2770 server.get(&"/form").await.assert_form(&ExampleResponse {
2771 name: "Joe".to_string(),
2772 age: 20,
2773 });
2774 }
2775
2776 #[tokio::test]
2777 #[should_panic]
2778 async fn it_should_panic_if_response_is_different() {
2779 let app = Router::new().route(&"/form", get(route_get_form));
2780
2781 let server = TestServer::new(app).unwrap();
2782
2783 server.get(&"/form").await.assert_form(&ExampleResponse {
2784 name: "Julia".to_string(),
2785 age: 25,
2786 });
2787 }
2788
2789 #[tokio::test]
2790 #[should_panic]
2791 async fn it_should_panic_if_response_is_json() {
2792 let app = Router::new().route(&"/json", get(route_get_json));
2793
2794 let server = TestServer::new(app).unwrap();
2795
2796 server.get(&"/json").await.assert_form(&ExampleResponse {
2797 name: "Joe".to_string(),
2798 age: 20,
2799 });
2800 }
2801}
2802
2803#[cfg(test)]
2804mod test_text {
2805 use crate::TestServer;
2806 use axum::routing::get;
2807 use axum::Router;
2808
2809 #[tokio::test]
2810 async fn it_should_deserialize_into_text() {
2811 async fn route_get_text() -> String {
2812 "hello!".to_string()
2813 }
2814
2815 let app = Router::new().route(&"/text", get(route_get_text));
2816
2817 let server = TestServer::new(app).unwrap();
2818
2819 let response = server.get(&"/text").await.text();
2820
2821 assert_eq!(response, "hello!");
2822 }
2823}
2824
2825#[cfg(feature = "ws")]
2826#[cfg(test)]
2827mod test_into_websocket {
2828 use crate::TestServer;
2829
2830 use axum::extract::ws::WebSocket;
2831 use axum::extract::WebSocketUpgrade;
2832 use axum::response::Response;
2833 use axum::routing::get;
2834 use axum::Router;
2835
2836 fn new_test_router() -> Router {
2837 pub async fn route_get_websocket(ws: WebSocketUpgrade) -> Response {
2838 async fn handle_ping_pong(mut socket: WebSocket) {
2839 while let Some(_) = socket.recv().await {
2840 }
2842 }
2843
2844 ws.on_upgrade(move |socket| handle_ping_pong(socket))
2845 }
2846
2847 let app = Router::new().route(&"/ws", get(route_get_websocket));
2848
2849 app
2850 }
2851
2852 #[tokio::test]
2853 async fn it_should_upgrade_on_http_transport() {
2854 let router = new_test_router();
2855 let server = TestServer::builder()
2856 .http_transport()
2857 .build(router)
2858 .unwrap();
2859
2860 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2861
2862 assert!(true);
2863 }
2864
2865 #[tokio::test]
2866 #[should_panic]
2867 async fn it_should_fail_to_upgrade_on_mock_transport() {
2868 let router = new_test_router();
2869 let server = TestServer::builder()
2870 .mock_transport()
2871 .build(router)
2872 .unwrap();
2873
2874 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2875 }
2876}