1use crate::internals::DebugResponseBody;
2use crate::internals::RequestPathFormatter;
3use crate::internals::StatusCodeFormatter;
4use crate::internals::TryIntoRangeBounds;
5use crate::internals::format_status_code_range;
6use anyhow::Context;
7use bytes::Bytes;
8use cookie::Cookie;
9use cookie::CookieJar;
10use http::HeaderMap;
11use http::HeaderValue;
12use http::Method;
13use http::StatusCode;
14use http::header::HeaderName;
15use http::header::SET_COOKIE;
16use http::response::Parts;
17use serde::Serialize;
18use serde::de::DeserializeOwned;
19use serde_json::Value;
20use std::convert::AsRef;
21use std::fmt::Debug;
22use std::fmt::Display;
23use std::fs::File;
24use std::fs::read_to_string;
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::TestWebSocket;
35#[cfg(feature = "ws")]
36use crate::internals::TestResponseWebSocket;
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!(
573 has_header,
574 "Expected header '{debug_header_name}' to be present in response, header was not found, for request {debug_request_format}"
575 );
576 }
577
578 #[track_caller]
579 pub fn assert_header<N, V>(&self, name: N, value: V)
580 where
581 N: TryInto<HeaderName> + Display + Clone,
582 N::Error: Debug,
583 V: TryInto<HeaderValue>,
584 V::Error: Debug,
585 {
586 let debug_header_name = name.clone();
587 let header_name = name
588 .try_into()
589 .expect("Failed to build HeaderName from name given");
590 let expected_header_value = value
591 .try_into()
592 .expect("Could not turn given value into HeaderValue");
593 let debug_request_format = self.debug_request_format();
594 let maybe_found_header_value = self.maybe_header(header_name);
595
596 match maybe_found_header_value {
597 None => {
598 panic!(
599 "Expected header '{debug_header_name}' to be present in response, header was not found, for request {debug_request_format}"
600 )
601 }
602 Some(found_header_value) => {
603 assert_eq!(expected_header_value, found_header_value,)
604 }
605 }
606 }
607
608 #[must_use]
614 pub fn maybe_cookie(&self, cookie_name: &str) -> Option<Cookie<'static>> {
615 for cookie in self.iter_cookies() {
616 if cookie.name() == cookie_name {
617 return Some(cookie.into_owned());
618 }
619 }
620
621 None
622 }
623
624 #[must_use]
630 pub fn cookie(&self, cookie_name: &str) -> Cookie<'static> {
631 self.maybe_cookie(cookie_name)
632 .with_context(|| {
633 let debug_request_format = self.debug_request_format();
634
635 format!("Cannot find cookie {cookie_name}, for request {debug_request_format}")
636 })
637 .unwrap()
638 }
639
640 #[must_use]
645 pub fn cookies(&self) -> CookieJar {
646 let mut cookies = CookieJar::new();
647
648 for cookie in self.iter_cookies() {
649 cookies.add(cookie.into_owned());
650 }
651
652 cookies
653 }
654
655 pub fn iter_cookies(&self) -> impl Iterator<Item = Cookie<'_>> {
657 self.iter_headers_by_name(SET_COOKIE).map(|header| {
658 let header_str = header
659 .to_str()
660 .with_context(|| {
661 let debug_request_format = self.debug_request_format();
662
663 format!(
664 "Reading header 'Set-Cookie' as string, for request {debug_request_format}",
665 )
666 })
667 .unwrap();
668
669 Cookie::parse(header_str)
670 .with_context(|| {
671 let debug_request_format = self.debug_request_format();
672
673 format!("Parsing 'Set-Cookie' header, for request {debug_request_format}",)
674 })
675 .unwrap()
676 })
677 }
678
679 #[cfg(feature = "ws")]
711 #[must_use]
712 pub async fn into_websocket(self) -> TestWebSocket {
713 use crate::transport_layer::TransportLayerType;
714
715 if self.websockets.transport_type != TransportLayerType::Http {
717 unimplemented!(
718 "WebSocket requires a HTTP based transport layer, see `TestServerConfig::transport`"
719 );
720 }
721
722 let debug_request_format = self.debug_request_format().to_string();
723
724 let on_upgrade = self.websockets.maybe_on_upgrade.with_context(|| {
725 format!("Expected WebSocket upgrade to be found, it is None, for request {debug_request_format}")
726 })
727 .unwrap();
728
729 let upgraded = on_upgrade
730 .await
731 .with_context(|| {
732 format!("Failed to upgrade connection for, for request {debug_request_format}")
733 })
734 .unwrap();
735
736 TestWebSocket::new(upgraded).await
737 }
738
739 #[track_caller]
742 pub fn assert_text<C>(&self, expected: C)
743 where
744 C: AsRef<str>,
745 {
746 let expected_contents = expected.as_ref();
747 assert_eq!(expected_contents, &self.text());
748 }
749
750 #[track_caller]
752 pub fn assert_text_contains<C>(&self, expected: C)
753 where
754 C: AsRef<str>,
755 {
756 let expected_contents = expected.as_ref();
757 let received = self.text();
758 let is_contained = received.contains(expected_contents);
759
760 assert!(
761 is_contained,
762 "Failed to find '{expected_contents}', received '{received}'"
763 );
764 }
765
766 #[track_caller]
768 pub fn assert_text_from_file<P>(&self, path: P)
769 where
770 P: AsRef<Path>,
771 {
772 let path_ref = path.as_ref();
773 let expected = read_to_string(path_ref)
774 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
775 .unwrap();
776
777 self.assert_text(expected);
778 }
779
780 #[track_caller]
829 pub fn assert_json<T>(&self, expected: &T)
830 where
831 T: Serialize + DeserializeOwned + PartialEq<T> + Debug,
832 {
833 let received = self.json::<T>();
834
835 #[cfg(feature = "old-json-diff")]
836 {
837 assert_eq!(*expected, received);
838 }
839
840 #[cfg(not(feature = "old-json-diff"))]
841 {
842 if *expected != received {
843 if let Err(error) = expect_json_eq(&received, &expected) {
844 panic!(
845 "
846{error}
847",
848 );
849 }
850 }
851 }
852 }
853
854 #[track_caller]
892 pub fn assert_json_contains<T>(&self, expected: &T)
893 where
894 T: Serialize,
895 {
896 let received = self.json::<Value>();
897
898 #[cfg(feature = "old-json-diff")]
899 {
900 assert_json_diff::assert_json_include!(actual: received, expected: expected);
901 }
902
903 #[cfg(not(feature = "old-json-diff"))]
904 {
905 let expected_value = serde_json::to_value(expected).unwrap();
906 let result = expect_json_eq(
907 &received,
908 &expect::object().propagated_contains(expected_value),
909 );
910 if let Err(error) = result {
911 panic!(
912 "
913{error}
914",
915 );
916 }
917 }
918 }
919
920 #[track_caller]
949 pub fn assert_json_from_file<P>(&self, path: P)
950 where
951 P: AsRef<Path>,
952 {
953 let path_ref = path.as_ref();
954 let file = File::open(path_ref)
955 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
956 .unwrap();
957
958 let reader = BufReader::new(file);
959 let expected = serde_json::from_reader::<_, serde_json::Value>(reader)
960 .with_context(|| {
961 format!(
962 "Failed to deserialize file '{}' as json",
963 path_ref.display()
964 )
965 })
966 .unwrap();
967
968 self.assert_json(&expected);
969 }
970
971 #[cfg(feature = "yaml")]
977 #[track_caller]
978 pub fn assert_yaml<T>(&self, other: &T)
979 where
980 T: DeserializeOwned + PartialEq<T> + Debug,
981 {
982 assert_eq!(*other, self.yaml::<T>());
983 }
984
985 #[cfg(feature = "yaml")]
987 #[track_caller]
988 pub fn assert_yaml_from_file<P>(&self, path: P)
989 where
990 P: AsRef<Path>,
991 {
992 let path_ref = path.as_ref();
993 let file = File::open(path_ref)
994 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
995 .unwrap();
996
997 let reader = BufReader::new(file);
998 let expected = serde_yaml::from_reader::<_, serde_yaml::Value>(reader)
999 .with_context(|| {
1000 format!(
1001 "Failed to deserialize file '{}' as yaml",
1002 path_ref.display()
1003 )
1004 })
1005 .unwrap();
1006
1007 self.assert_yaml(&expected);
1008 }
1009
1010 #[cfg(feature = "msgpack")]
1016 #[track_caller]
1017 pub fn assert_msgpack<T>(&self, other: &T)
1018 where
1019 T: DeserializeOwned + PartialEq<T> + Debug,
1020 {
1021 assert_eq!(*other, self.msgpack::<T>());
1022 }
1023
1024 #[track_caller]
1030 pub fn assert_form<T>(&self, other: &T)
1031 where
1032 T: DeserializeOwned + PartialEq<T> + Debug,
1033 {
1034 assert_eq!(*other, self.form::<T>());
1035 }
1036
1037 #[track_caller]
1039 pub fn assert_status(&self, expected_status_code: StatusCode) {
1040 let received_debug = StatusCodeFormatter(self.status_code);
1041 let expected_debug = StatusCodeFormatter(expected_status_code);
1042 let debug_request_format = self.debug_request_format();
1043 let debug_body = DebugResponseBody(self);
1044
1045 assert_eq!(
1046 expected_status_code, self.status_code,
1047 "Expected status code to be {expected_debug}, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1048 );
1049 }
1050
1051 #[track_caller]
1053 pub fn assert_not_status(&self, expected_status_code: StatusCode) {
1054 let received_debug = StatusCodeFormatter(self.status_code);
1055 let expected_debug = StatusCodeFormatter(expected_status_code);
1056 let debug_request_format = self.debug_request_format();
1057 let debug_body = DebugResponseBody(self);
1058
1059 assert_ne!(
1060 expected_status_code, self.status_code,
1061 "Expected status code to not be {expected_debug}, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1062 );
1063 }
1064
1065 #[track_caller]
1068 pub fn assert_status_success(&self) {
1069 let status_code = self.status_code.as_u16();
1070 let received_debug = StatusCodeFormatter(self.status_code);
1071 let debug_request_format = self.debug_request_format();
1072 let debug_body = DebugResponseBody(self);
1073
1074 assert!(
1075 200 <= status_code && status_code <= 299,
1076 "Expect status code within 2xx range, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1077 );
1078 }
1079
1080 #[track_caller]
1083 pub fn assert_status_failure(&self) {
1084 let status_code = self.status_code.as_u16();
1085 let received_debug = StatusCodeFormatter(self.status_code);
1086 let debug_request_format = self.debug_request_format();
1087 let debug_body = DebugResponseBody(self);
1088
1089 assert!(
1090 status_code < 200 || 299 < status_code,
1091 "Expect status code outside 2xx range, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1092 );
1093 }
1094
1095 #[track_caller]
1133 pub fn assert_status_in_range<R, S>(&self, expected_status_range: R)
1134 where
1135 R: RangeBounds<S> + TryIntoRangeBounds<StatusCode> + Debug,
1136 S: TryInto<StatusCode>,
1137 {
1138 let range = TryIntoRangeBounds::<StatusCode>::try_into_range_bounds(expected_status_range)
1139 .expect("Failed to convert status code");
1140
1141 let status_code = self.status_code();
1142 let is_in_range = range.contains(&status_code);
1143 let debug_request_format = self.debug_request_format();
1144 let debug_body = DebugResponseBody(self);
1145
1146 assert!(
1147 is_in_range,
1148 "Expected status to be in range {}, received {status_code}, for request {debug_request_format}, with body {debug_body}",
1149 format_status_code_range(range)
1150 );
1151 }
1152
1153 #[track_caller]
1191 pub fn assert_status_not_in_range<R, S>(&self, expected_status_range: R)
1192 where
1193 R: RangeBounds<S> + TryIntoRangeBounds<StatusCode> + Debug,
1194 S: TryInto<StatusCode>,
1195 {
1196 let range = TryIntoRangeBounds::<StatusCode>::try_into_range_bounds(expected_status_range)
1197 .expect("Failed to convert status code");
1198
1199 let status_code = self.status_code();
1200 let is_not_in_range = !range.contains(&status_code);
1201 let debug_request_format = self.debug_request_format();
1202 let debug_body = DebugResponseBody(self);
1203
1204 assert!(
1205 is_not_in_range,
1206 "Expected status is not in range {}, received {status_code}, for request {debug_request_format}, with body {debug_body}",
1207 format_status_code_range(range)
1208 );
1209 }
1210
1211 #[track_caller]
1213 pub fn assert_status_ok(&self) {
1214 self.assert_status(StatusCode::OK)
1215 }
1216
1217 #[track_caller]
1219 pub fn assert_status_not_ok(&self) {
1220 self.assert_not_status(StatusCode::OK)
1221 }
1222
1223 #[track_caller]
1225 pub fn assert_status_no_content(&self) {
1226 self.assert_status(StatusCode::NO_CONTENT)
1227 }
1228
1229 #[track_caller]
1231 pub fn assert_status_see_other(&self) {
1232 self.assert_status(StatusCode::SEE_OTHER)
1233 }
1234
1235 #[track_caller]
1237 pub fn assert_status_bad_request(&self) {
1238 self.assert_status(StatusCode::BAD_REQUEST)
1239 }
1240
1241 #[track_caller]
1243 pub fn assert_status_not_found(&self) {
1244 self.assert_status(StatusCode::NOT_FOUND)
1245 }
1246
1247 #[track_caller]
1249 pub fn assert_status_unauthorized(&self) {
1250 self.assert_status(StatusCode::UNAUTHORIZED)
1251 }
1252
1253 #[track_caller]
1255 pub fn assert_status_forbidden(&self) {
1256 self.assert_status(StatusCode::FORBIDDEN)
1257 }
1258
1259 pub fn assert_status_conflict(&self) {
1261 self.assert_status(StatusCode::CONFLICT)
1262 }
1263
1264 #[track_caller]
1268 pub fn assert_status_payload_too_large(&self) {
1269 self.assert_status(StatusCode::PAYLOAD_TOO_LARGE)
1270 }
1271
1272 #[track_caller]
1274 pub fn assert_status_unprocessable_entity(&self) {
1275 self.assert_status(StatusCode::UNPROCESSABLE_ENTITY)
1276 }
1277
1278 #[track_caller]
1280 pub fn assert_status_too_many_requests(&self) {
1281 self.assert_status(StatusCode::TOO_MANY_REQUESTS)
1282 }
1283
1284 #[track_caller]
1289 pub fn assert_status_switching_protocols(&self) {
1290 self.assert_status(StatusCode::SWITCHING_PROTOCOLS)
1291 }
1292
1293 #[track_caller]
1295 pub fn assert_status_internal_server_error(&self) {
1296 self.assert_status(StatusCode::INTERNAL_SERVER_ERROR)
1297 }
1298
1299 #[track_caller]
1301 pub fn assert_status_service_unavailable(&self) {
1302 self.assert_status(StatusCode::SERVICE_UNAVAILABLE)
1303 }
1304
1305 fn debug_request_format(&self) -> RequestPathFormatter<'_> {
1306 RequestPathFormatter::new(&self.method, self.full_request_url.as_str(), None)
1307 }
1308}
1309
1310impl From<TestResponse> for Bytes {
1311 fn from(response: TestResponse) -> Self {
1312 response.into_bytes()
1313 }
1314}
1315
1316#[cfg(test)]
1317mod test_assert_header {
1318 use crate::TestServer;
1319 use axum::Router;
1320 use axum::http::HeaderMap;
1321 use axum::routing::get;
1322
1323 async fn route_get_header() -> HeaderMap {
1324 let mut headers = HeaderMap::new();
1325 headers.insert("x-my-custom-header", "content".parse().unwrap());
1326 headers
1327 }
1328
1329 #[tokio::test]
1330 async fn it_should_not_panic_if_contains_header_and_content_matches() {
1331 let router = Router::new().route(&"/header", get(route_get_header));
1332
1333 let server = TestServer::new(router).unwrap();
1334
1335 server
1336 .get(&"/header")
1337 .await
1338 .assert_header("x-my-custom-header", "content");
1339 }
1340
1341 #[tokio::test]
1342 #[should_panic]
1343 async fn it_should_panic_if_contains_header_and_content_does_not_match() {
1344 let router = Router::new().route(&"/header", get(route_get_header));
1345
1346 let server = TestServer::new(router).unwrap();
1347
1348 server
1349 .get(&"/header")
1350 .await
1351 .assert_header("x-my-custom-header", "different-content");
1352 }
1353
1354 #[tokio::test]
1355 #[should_panic]
1356 async fn it_should_panic_if_not_contains_header() {
1357 let router = Router::new().route(&"/header", get(route_get_header));
1358
1359 let server = TestServer::new(router).unwrap();
1360
1361 server
1362 .get(&"/header")
1363 .await
1364 .assert_header("x-custom-header-not-found", "content");
1365 }
1366}
1367
1368#[cfg(test)]
1369mod test_assert_contains_header {
1370 use crate::TestServer;
1371 use axum::Router;
1372 use axum::http::HeaderMap;
1373 use axum::routing::get;
1374
1375 async fn route_get_header() -> HeaderMap {
1376 let mut headers = HeaderMap::new();
1377 headers.insert("x-my-custom-header", "content".parse().unwrap());
1378 headers
1379 }
1380
1381 #[tokio::test]
1382 async fn it_should_not_panic_if_contains_header() {
1383 let router = Router::new().route(&"/header", get(route_get_header));
1384
1385 let server = TestServer::new(router).unwrap();
1386
1387 server
1388 .get(&"/header")
1389 .await
1390 .assert_contains_header("x-my-custom-header");
1391 }
1392
1393 #[tokio::test]
1394 #[should_panic]
1395 async fn it_should_panic_if_not_contains_header() {
1396 let router = Router::new().route(&"/header", get(route_get_header));
1397
1398 let server = TestServer::new(router).unwrap();
1399
1400 server
1401 .get(&"/header")
1402 .await
1403 .assert_contains_header("x-custom-header-not-found");
1404 }
1405}
1406
1407#[cfg(test)]
1408mod test_assert_success {
1409 use crate::TestServer;
1410 use axum::Router;
1411 use axum::routing::get;
1412 use http::StatusCode;
1413
1414 pub async fn route_get_pass() -> StatusCode {
1415 StatusCode::OK
1416 }
1417
1418 pub async fn route_get_fail() -> StatusCode {
1419 StatusCode::SERVICE_UNAVAILABLE
1420 }
1421
1422 #[tokio::test]
1423 async fn it_should_pass_when_200() {
1424 let router = Router::new()
1425 .route(&"/pass", get(route_get_pass))
1426 .route(&"/fail", get(route_get_fail));
1427
1428 let server = TestServer::new(router).unwrap();
1429
1430 let response = server.get(&"/pass").await;
1431
1432 response.assert_status_success()
1433 }
1434
1435 #[tokio::test]
1436 #[should_panic]
1437 async fn it_should_panic_when_not_200() {
1438 let router = Router::new()
1439 .route(&"/pass", get(route_get_pass))
1440 .route(&"/fail", get(route_get_fail));
1441
1442 let server = TestServer::new(router).unwrap();
1443
1444 let response = server.get(&"/fail").expect_failure().await;
1445
1446 response.assert_status_success()
1447 }
1448}
1449
1450#[cfg(test)]
1451mod test_assert_failure {
1452 use crate::TestServer;
1453 use axum::Router;
1454 use axum::routing::get;
1455 use http::StatusCode;
1456
1457 pub async fn route_get_pass() -> StatusCode {
1458 StatusCode::OK
1459 }
1460
1461 pub async fn route_get_fail() -> StatusCode {
1462 StatusCode::SERVICE_UNAVAILABLE
1463 }
1464
1465 #[tokio::test]
1466 async fn it_should_pass_when_not_200() {
1467 let router = Router::new()
1468 .route(&"/pass", get(route_get_pass))
1469 .route(&"/fail", get(route_get_fail));
1470
1471 let server = TestServer::new(router).unwrap();
1472 let response = server.get(&"/fail").expect_failure().await;
1473
1474 response.assert_status_failure()
1475 }
1476
1477 #[tokio::test]
1478 #[should_panic]
1479 async fn it_should_panic_when_200() {
1480 let router = Router::new()
1481 .route(&"/pass", get(route_get_pass))
1482 .route(&"/fail", get(route_get_fail));
1483
1484 let server = TestServer::new(router).unwrap();
1485 let response = server.get(&"/pass").await;
1486
1487 response.assert_status_failure()
1488 }
1489}
1490
1491#[cfg(test)]
1492mod test_assert_status {
1493 use crate::TestServer;
1494 use axum::Router;
1495 use axum::routing::get;
1496 use http::StatusCode;
1497
1498 pub async fn route_get_ok() -> StatusCode {
1499 StatusCode::OK
1500 }
1501
1502 #[tokio::test]
1503 async fn it_should_pass_if_given_right_status_code() {
1504 let router = Router::new().route(&"/ok", get(route_get_ok));
1505 let server = TestServer::new(router).unwrap();
1506
1507 server.get(&"/ok").await.assert_status(StatusCode::OK);
1508 }
1509
1510 #[tokio::test]
1511 #[should_panic]
1512 async fn it_should_panic_when_status_code_does_not_match() {
1513 let router = Router::new().route(&"/ok", get(route_get_ok));
1514 let server = TestServer::new(router).unwrap();
1515
1516 server.get(&"/ok").await.assert_status(StatusCode::ACCEPTED);
1517 }
1518}
1519
1520#[cfg(test)]
1521mod test_assert_not_status {
1522 use crate::TestServer;
1523 use axum::Router;
1524 use axum::routing::get;
1525 use http::StatusCode;
1526
1527 pub async fn route_get_ok() -> StatusCode {
1528 StatusCode::OK
1529 }
1530
1531 #[tokio::test]
1532 async fn it_should_pass_if_status_code_does_not_match() {
1533 let router = Router::new().route(&"/ok", get(route_get_ok));
1534 let server = TestServer::new(router).unwrap();
1535
1536 server
1537 .get(&"/ok")
1538 .await
1539 .assert_not_status(StatusCode::ACCEPTED);
1540 }
1541
1542 #[tokio::test]
1543 #[should_panic]
1544 async fn it_should_panic_if_status_code_matches() {
1545 let router = Router::new().route(&"/ok", get(route_get_ok));
1546 let server = TestServer::new(router).unwrap();
1547
1548 server.get(&"/ok").await.assert_not_status(StatusCode::OK);
1549 }
1550}
1551
1552#[cfg(test)]
1553mod test_assert_status_in_range {
1554 use crate::TestServer;
1555 use axum::routing::Router;
1556 use axum::routing::get;
1557 use http::StatusCode;
1558 use std::ops::RangeFull;
1559
1560 #[tokio::test]
1561 async fn it_should_be_true_when_within_int_range() {
1562 let app = Router::new().route(
1563 &"/status",
1564 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1565 );
1566
1567 TestServer::new(app)
1568 .unwrap()
1569 .get(&"/status")
1570 .await
1571 .assert_status_in_range(200..299);
1572 }
1573
1574 #[tokio::test]
1575 async fn it_should_be_true_when_within_status_code_range() {
1576 let app = Router::new().route(
1577 &"/status",
1578 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1579 );
1580
1581 TestServer::new(app)
1582 .unwrap()
1583 .get(&"/status")
1584 .await
1585 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1586 }
1587
1588 #[tokio::test]
1589 #[should_panic]
1590 async fn it_should_be_false_when_outside_int_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(200..299);
1601 }
1602
1603 #[tokio::test]
1604 #[should_panic]
1605 async fn it_should_be_false_when_outside_status_code_range() {
1606 let app = Router::new().route(
1607 &"/status",
1608 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1609 );
1610
1611 TestServer::new(app)
1612 .unwrap()
1613 .get(&"/status")
1614 .await
1615 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1616 }
1617
1618 #[tokio::test]
1619 async fn it_should_be_true_when_within_inclusive_range() {
1620 let app = Router::new().route(
1621 &"/status",
1622 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
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 #[should_panic]
1634 async fn it_should_be_false_when_outside_inclusive_range() {
1635 let app = Router::new().route(
1636 &"/status",
1637 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1638 );
1639
1640 TestServer::new(app)
1641 .unwrap()
1642 .get(&"/status")
1643 .await
1644 .assert_status_in_range(200..=299);
1645 }
1646
1647 #[tokio::test]
1648 async fn it_should_be_true_when_within_to_range() {
1649 let app = Router::new().route(
1650 &"/status",
1651 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
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 #[should_panic]
1663 async fn it_should_be_false_when_outside_to_range() {
1664 let app = Router::new().route(
1665 &"/status",
1666 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1667 );
1668
1669 TestServer::new(app)
1670 .unwrap()
1671 .get(&"/status")
1672 .await
1673 .assert_status_in_range(..299);
1674 }
1675
1676 #[tokio::test]
1677 async fn it_should_be_true_when_within_to_inclusive_range() {
1678 let app = Router::new().route(
1679 &"/status",
1680 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
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 #[should_panic]
1692 async fn it_should_be_false_when_outside_to_inclusive_range() {
1693 let app = Router::new().route(
1694 &"/status",
1695 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1696 );
1697
1698 TestServer::new(app)
1699 .unwrap()
1700 .get(&"/status")
1701 .await
1702 .assert_status_in_range(..=299);
1703 }
1704
1705 #[tokio::test]
1706 async fn it_should_be_true_when_within_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(200..);
1717 }
1718
1719 #[tokio::test]
1720 #[should_panic]
1721 async fn it_should_be_false_when_outside_from_range() {
1722 let app = Router::new().route(
1723 &"/status",
1724 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1725 );
1726
1727 TestServer::new(app)
1728 .unwrap()
1729 .get(&"/status")
1730 .await
1731 .assert_status_in_range(500..);
1732 }
1733
1734 #[tokio::test]
1735 async fn it_should_be_true_for_rull_range() {
1736 let app = Router::new().route(
1737 &"/status",
1738 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1739 );
1740
1741 TestServer::new(app)
1742 .unwrap()
1743 .get(&"/status")
1744 .await
1745 .assert_status_in_range::<RangeFull, StatusCode>(..);
1746 }
1747}
1748
1749#[cfg(test)]
1750mod test_assert_status_not_in_range {
1751 use crate::TestServer;
1752 use axum::routing::Router;
1753 use axum::routing::get;
1754 use http::StatusCode;
1755 use std::ops::RangeFull;
1756
1757 #[tokio::test]
1758 #[should_panic]
1759 async fn it_should_be_false_when_within_int_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(200..299);
1770 }
1771
1772 #[tokio::test]
1773 #[should_panic]
1774 async fn it_should_be_false_when_within_status_code_range() {
1775 let app = Router::new().route(
1776 &"/status",
1777 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1778 );
1779
1780 TestServer::new(app)
1781 .unwrap()
1782 .get(&"/status")
1783 .await
1784 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1785 }
1786
1787 #[tokio::test]
1788 async fn it_should_be_true_when_outside_int_range() {
1789 let app = Router::new().route(
1790 &"/status",
1791 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1792 );
1793
1794 TestServer::new(app)
1795 .unwrap()
1796 .get(&"/status")
1797 .await
1798 .assert_status_not_in_range(200..299);
1799 }
1800
1801 #[tokio::test]
1802 async fn it_should_be_true_when_outside_status_code_range() {
1803 let app = Router::new().route(
1804 &"/status",
1805 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1806 );
1807
1808 TestServer::new(app)
1809 .unwrap()
1810 .get(&"/status")
1811 .await
1812 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1813 }
1814
1815 #[tokio::test]
1816 #[should_panic]
1817 async fn it_should_be_false_when_within_inclusive_range() {
1818 let app = Router::new().route(
1819 &"/status",
1820 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1821 );
1822
1823 TestServer::new(app)
1824 .unwrap()
1825 .get(&"/status")
1826 .await
1827 .assert_status_not_in_range(200..=299);
1828 }
1829
1830 #[tokio::test]
1831 async fn it_should_be_true_when_outside_inclusive_range() {
1832 let app = Router::new().route(
1833 &"/status",
1834 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1835 );
1836
1837 TestServer::new(app)
1838 .unwrap()
1839 .get(&"/status")
1840 .await
1841 .assert_status_not_in_range(200..=299);
1842 }
1843
1844 #[tokio::test]
1845 #[should_panic]
1846 async fn it_should_be_false_when_within_to_range() {
1847 let app = Router::new().route(
1848 &"/status",
1849 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1850 );
1851
1852 TestServer::new(app)
1853 .unwrap()
1854 .get(&"/status")
1855 .await
1856 .assert_status_not_in_range(..299);
1857 }
1858
1859 #[tokio::test]
1860 async fn it_should_be_true_when_outside_to_range() {
1861 let app = Router::new().route(
1862 &"/status",
1863 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
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 #[should_panic]
1875 async fn it_should_be_false_when_within_to_inclusive_range() {
1876 let app = Router::new().route(
1877 &"/status",
1878 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1879 );
1880
1881 TestServer::new(app)
1882 .unwrap()
1883 .get(&"/status")
1884 .await
1885 .assert_status_not_in_range(..=299);
1886 }
1887
1888 #[tokio::test]
1889 async fn it_should_be_true_when_outside_to_inclusive_range() {
1890 let app = Router::new().route(
1891 &"/status",
1892 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1893 );
1894
1895 TestServer::new(app)
1896 .unwrap()
1897 .get(&"/status")
1898 .await
1899 .assert_status_not_in_range(..=299);
1900 }
1901
1902 #[tokio::test]
1903 #[should_panic]
1904 async fn it_should_be_false_when_within_from_range() {
1905 let app = Router::new().route(
1906 &"/status",
1907 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1908 );
1909
1910 TestServer::new(app)
1911 .unwrap()
1912 .get(&"/status")
1913 .await
1914 .assert_status_not_in_range(200..);
1915 }
1916
1917 #[tokio::test]
1918 async fn it_should_be_true_when_outside_from_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(500..);
1929 }
1930
1931 #[tokio::test]
1932 #[should_panic]
1933 async fn it_should_be_false_for_rull_range() {
1934 let app = Router::new().route(
1935 &"/status",
1936 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1937 );
1938
1939 TestServer::new(app)
1940 .unwrap()
1941 .get(&"/status")
1942 .await
1943 .assert_status_not_in_range::<RangeFull, StatusCode>(..);
1944 }
1945}
1946
1947#[cfg(test)]
1948mod test_into_bytes {
1949 use crate::TestServer;
1950 use axum::Json;
1951 use axum::Router;
1952 use axum::routing::get;
1953 use serde_json::Value;
1954 use serde_json::json;
1955
1956 async fn route_get_json() -> Json<Value> {
1957 Json(json!({
1958 "message": "it works?"
1959 }))
1960 }
1961
1962 #[tokio::test]
1963 async fn it_should_deserialize_into_json() {
1964 let app = Router::new().route(&"/json", get(route_get_json));
1965
1966 let server = TestServer::new(app).unwrap();
1967
1968 let bytes = server.get(&"/json").await.into_bytes();
1969 let text = String::from_utf8_lossy(&bytes);
1970
1971 assert_eq!(text, r#"{"message":"it works?"}"#);
1972 }
1973}
1974
1975#[cfg(test)]
1976mod test_content_type {
1977 use crate::TestServer;
1978 use axum::Json;
1979 use axum::Router;
1980 use axum::routing::get;
1981 use serde::Deserialize;
1982 use serde::Serialize;
1983
1984 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1985 struct ExampleResponse {
1986 name: String,
1987 age: u32,
1988 }
1989
1990 #[tokio::test]
1991 async fn it_should_retrieve_json_content_type_for_json() {
1992 let app = Router::new().route(
1993 &"/json",
1994 get(|| async {
1995 Json(ExampleResponse {
1996 name: "Joe".to_string(),
1997 age: 20,
1998 })
1999 }),
2000 );
2001
2002 let server = TestServer::new(app).unwrap();
2003
2004 let content_type = server.get(&"/json").await.content_type();
2005 assert_eq!(content_type, "application/json");
2006 }
2007
2008 #[cfg(feature = "yaml")]
2009 #[tokio::test]
2010 async fn it_should_retrieve_yaml_content_type_for_yaml() {
2011 use axum_yaml::Yaml;
2012
2013 let app = Router::new().route(
2014 &"/yaml",
2015 get(|| async {
2016 Yaml(ExampleResponse {
2017 name: "Joe".to_string(),
2018 age: 20,
2019 })
2020 }),
2021 );
2022
2023 let server = TestServer::new(app).unwrap();
2024
2025 let content_type = server.get(&"/yaml").await.content_type();
2026 assert_eq!(content_type, "application/yaml");
2027 }
2028}
2029
2030#[cfg(test)]
2031mod test_json {
2032 use crate::TestServer;
2033 use axum::Json;
2034 use axum::Router;
2035 use axum::routing::get;
2036 use serde::Deserialize;
2037 use serde::Serialize;
2038
2039 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2040 struct ExampleResponse {
2041 name: String,
2042 age: u32,
2043 }
2044
2045 async fn route_get_json() -> Json<ExampleResponse> {
2046 Json(ExampleResponse {
2047 name: "Joe".to_string(),
2048 age: 20,
2049 })
2050 }
2051
2052 #[tokio::test]
2053 async fn it_should_deserialize_into_json() {
2054 let app = Router::new().route(&"/json", get(route_get_json));
2055
2056 let server = TestServer::new(app).unwrap();
2057
2058 let response = server.get(&"/json").await.json::<ExampleResponse>();
2059
2060 assert_eq!(
2061 response,
2062 ExampleResponse {
2063 name: "Joe".to_string(),
2064 age: 20,
2065 }
2066 );
2067 }
2068}
2069
2070#[cfg(feature = "yaml")]
2071#[cfg(test)]
2072mod test_yaml {
2073 use crate::TestServer;
2074 use axum::Router;
2075 use axum::routing::get;
2076 use axum_yaml::Yaml;
2077 use serde::Deserialize;
2078 use serde::Serialize;
2079
2080 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2081 struct ExampleResponse {
2082 name: String,
2083 age: u32,
2084 }
2085
2086 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2087 Yaml(ExampleResponse {
2088 name: "Joe".to_string(),
2089 age: 20,
2090 })
2091 }
2092
2093 #[tokio::test]
2094 async fn it_should_deserialize_into_yaml() {
2095 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2096
2097 let server = TestServer::new(app).unwrap();
2098
2099 let response = server.get(&"/yaml").await.yaml::<ExampleResponse>();
2100
2101 assert_eq!(
2102 response,
2103 ExampleResponse {
2104 name: "Joe".to_string(),
2105 age: 20,
2106 }
2107 );
2108 }
2109}
2110
2111#[cfg(feature = "msgpack")]
2112#[cfg(test)]
2113mod test_msgpack {
2114 use crate::TestServer;
2115 use axum::Router;
2116 use axum::routing::get;
2117 use axum_msgpack::MsgPack;
2118 use serde::Deserialize;
2119 use serde::Serialize;
2120
2121 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2122 struct ExampleResponse {
2123 name: String,
2124 age: u32,
2125 }
2126
2127 async fn route_get_msgpack() -> MsgPack<ExampleResponse> {
2128 MsgPack(ExampleResponse {
2129 name: "Joe".to_string(),
2130 age: 20,
2131 })
2132 }
2133
2134 #[tokio::test]
2135 async fn it_should_deserialize_into_msgpack() {
2136 let app = Router::new().route(&"/msgpack", get(route_get_msgpack));
2137
2138 let server = TestServer::new(app).unwrap();
2139
2140 let response = server.get(&"/msgpack").await.msgpack::<ExampleResponse>();
2141
2142 assert_eq!(
2143 response,
2144 ExampleResponse {
2145 name: "Joe".to_string(),
2146 age: 20,
2147 }
2148 );
2149 }
2150}
2151
2152#[cfg(test)]
2153mod test_form {
2154 use crate::TestServer;
2155 use axum::Form;
2156 use axum::Router;
2157 use axum::routing::get;
2158 use serde::Deserialize;
2159 use serde::Serialize;
2160
2161 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2162 struct ExampleResponse {
2163 name: String,
2164 age: u32,
2165 }
2166
2167 async fn route_get_form() -> Form<ExampleResponse> {
2168 Form(ExampleResponse {
2169 name: "Joe".to_string(),
2170 age: 20,
2171 })
2172 }
2173
2174 #[tokio::test]
2175 async fn it_should_deserialize_into_form() {
2176 let app = Router::new().route(&"/form", get(route_get_form));
2177
2178 let server = TestServer::new(app).unwrap();
2179
2180 let response = server.get(&"/form").await.form::<ExampleResponse>();
2181
2182 assert_eq!(
2183 response,
2184 ExampleResponse {
2185 name: "Joe".to_string(),
2186 age: 20,
2187 }
2188 );
2189 }
2190}
2191
2192#[cfg(test)]
2193mod test_from {
2194 use crate::TestServer;
2195 use axum::Router;
2196 use axum::routing::get;
2197 use bytes::Bytes;
2198
2199 #[tokio::test]
2200 async fn it_should_turn_into_response_bytes() {
2201 let app = Router::new().route(&"/text", get(|| async { "This is some example text" }));
2202 let server = TestServer::new(app).unwrap();
2203
2204 let response = server.get(&"/text").await;
2205 let bytes: Bytes = response.into();
2206 let text = String::from_utf8_lossy(&bytes);
2207 assert_eq!(text, "This is some example text");
2208 }
2209}
2210
2211#[cfg(test)]
2212mod test_assert_text {
2213 use crate::TestServer;
2214 use axum::Router;
2215 use axum::routing::get;
2216
2217 fn new_test_server() -> TestServer {
2218 async fn route_get_text() -> &'static str {
2219 "This is some example text"
2220 }
2221
2222 let app = Router::new().route(&"/text", get(route_get_text));
2223 TestServer::new(app).unwrap()
2224 }
2225
2226 #[tokio::test]
2227 async fn it_should_match_whole_text() {
2228 let server = new_test_server();
2229
2230 server
2231 .get(&"/text")
2232 .await
2233 .assert_text("This is some example text");
2234 }
2235
2236 #[tokio::test]
2237 #[should_panic]
2238 async fn it_should_not_match_partial_text() {
2239 let server = new_test_server();
2240
2241 server.get(&"/text").await.assert_text("some example");
2242 }
2243
2244 #[tokio::test]
2245 #[should_panic]
2246 async fn it_should_not_match_different_text() {
2247 let server = new_test_server();
2248
2249 server.get(&"/text").await.assert_text("🦊");
2250 }
2251}
2252
2253#[cfg(test)]
2254mod test_assert_text_contains {
2255 use crate::TestServer;
2256 use axum::Router;
2257 use axum::routing::get;
2258
2259 fn new_test_server() -> TestServer {
2260 async fn route_get_text() -> &'static str {
2261 "This is some example text"
2262 }
2263
2264 let app = Router::new().route(&"/text", get(route_get_text));
2265 TestServer::new(app).unwrap()
2266 }
2267
2268 #[tokio::test]
2269 async fn it_should_match_whole_text() {
2270 let server = new_test_server();
2271
2272 server
2273 .get(&"/text")
2274 .await
2275 .assert_text_contains("This is some example text");
2276 }
2277
2278 #[tokio::test]
2279 async fn it_should_match_partial_text() {
2280 let server = new_test_server();
2281
2282 server
2283 .get(&"/text")
2284 .await
2285 .assert_text_contains("some example");
2286 }
2287
2288 #[tokio::test]
2289 #[should_panic]
2290 async fn it_should_not_match_different_text() {
2291 let server = new_test_server();
2292
2293 server.get(&"/text").await.assert_text_contains("🦊");
2294 }
2295}
2296
2297#[cfg(test)]
2298mod test_assert_text_from_file {
2299 use crate::TestServer;
2300 use axum::routing::Router;
2301 use axum::routing::get;
2302
2303 #[tokio::test]
2304 async fn it_should_match_from_file() {
2305 let app = Router::new().route(&"/text", get(|| async { "hello!" }));
2306 let server = TestServer::new(app).unwrap();
2307
2308 server
2309 .get(&"/text")
2310 .await
2311 .assert_text_from_file("files/example.txt");
2312 }
2313
2314 #[tokio::test]
2315 #[should_panic]
2316 async fn it_should_panic_when_not_match_the_file() {
2317 let app = Router::new().route(&"/text", get(|| async { "🦊" }));
2318 let server = TestServer::new(app).unwrap();
2319
2320 server
2321 .get(&"/text")
2322 .await
2323 .assert_text_from_file("files/example.txt");
2324 }
2325}
2326
2327#[cfg(test)]
2328mod test_assert_json {
2329 use super::*;
2330 use crate::TestServer;
2331 use axum::Form;
2332 use axum::Json;
2333 use axum::Router;
2334 use axum::routing::get;
2335 use serde::Deserialize;
2336 use serde_json::json;
2337
2338 #[cfg(not(feature = "old-json-diff"))]
2339 use crate::testing::ExpectStrMinLen;
2340
2341 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2342 struct ExampleResponse {
2343 name: String,
2344 age: u32,
2345 }
2346
2347 async fn route_get_form() -> Form<ExampleResponse> {
2348 Form(ExampleResponse {
2349 name: "Joe".to_string(),
2350 age: 20,
2351 })
2352 }
2353
2354 async fn route_get_json() -> Json<ExampleResponse> {
2355 Json(ExampleResponse {
2356 name: "Joe".to_string(),
2357 age: 20,
2358 })
2359 }
2360
2361 #[tokio::test]
2362 async fn it_should_match_json_returned() {
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: "Joe".to_string(),
2369 age: 20,
2370 });
2371 }
2372
2373 #[tokio::test]
2374 async fn it_should_match_json_returned_using_json_value() {
2375 let app = Router::new().route(&"/json", get(route_get_json));
2376
2377 let server = TestServer::new(app).unwrap();
2378
2379 server.get(&"/json").await.assert_json(&json!({
2380 "name": "Joe",
2381 "age": 20,
2382 }));
2383 }
2384
2385 #[tokio::test]
2386 #[should_panic]
2387 async fn it_should_panic_if_response_is_different() {
2388 let app = Router::new().route(&"/json", get(route_get_json));
2389
2390 let server = TestServer::new(app).unwrap();
2391
2392 server.get(&"/json").await.assert_json(&ExampleResponse {
2393 name: "Julia".to_string(),
2394 age: 25,
2395 });
2396 }
2397
2398 #[tokio::test]
2399 #[should_panic]
2400 async fn it_should_panic_if_response_is_form() {
2401 let app = Router::new().route(&"/form", get(route_get_form));
2402
2403 let server = TestServer::new(app).unwrap();
2404
2405 server.get(&"/form").await.assert_json(&ExampleResponse {
2406 name: "Joe".to_string(),
2407 age: 20,
2408 });
2409 }
2410
2411 #[cfg(not(feature = "old-json-diff"))]
2412 #[tokio::test]
2413 async fn it_should_work_with_custom_expect_op() {
2414 let app = Router::new().route(&"/json", get(route_get_json));
2415 let server = TestServer::new(app).unwrap();
2416
2417 server.get(&"/json").await.assert_json(&json!({
2418 "name": ExpectStrMinLen { min: 3 },
2419 "age": 20,
2420 }));
2421 }
2422
2423 #[cfg(not(feature = "old-json-diff"))]
2424 #[tokio::test]
2425 #[should_panic]
2426 async fn it_should_panic_if_custom_expect_op_fails() {
2427 let app = Router::new().route(&"/json", get(route_get_json));
2428 let server = TestServer::new(app).unwrap();
2429
2430 server.get(&"/json").await.assert_json(&json!({
2431 "name": ExpectStrMinLen { min: 10 },
2432 "age": 20,
2433 }));
2434 }
2435}
2436
2437#[cfg(test)]
2438mod test_assert_json_contains {
2439 use crate::TestServer;
2440 use axum::Form;
2441 use axum::Json;
2442 use axum::Router;
2443 use axum::routing::get;
2444 use serde::Deserialize;
2445 use serde::Serialize;
2446 use serde_json::json;
2447 use std::time::Instant;
2448
2449 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2450 struct ExampleResponse {
2451 time: u64,
2452 name: String,
2453 age: u32,
2454 }
2455
2456 async fn route_get_form() -> Form<ExampleResponse> {
2457 Form(ExampleResponse {
2458 time: Instant::now().elapsed().as_millis() as u64,
2459 name: "Joe".to_string(),
2460 age: 20,
2461 })
2462 }
2463
2464 async fn route_get_json() -> Json<ExampleResponse> {
2465 Json(ExampleResponse {
2466 time: Instant::now().elapsed().as_millis() as u64,
2467 name: "Joe".to_string(),
2468 age: 20,
2469 })
2470 }
2471
2472 #[tokio::test]
2473 async fn it_should_match_subset_of_json_returned() {
2474 let app = Router::new().route(&"/json", get(route_get_json));
2475 let server = TestServer::new(app).unwrap();
2476
2477 server.get(&"/json").await.assert_json_contains(&json!({
2478 "name": "Joe",
2479 "age": 20,
2480 }));
2481 }
2482
2483 #[tokio::test]
2484 #[should_panic]
2485 async fn it_should_panic_if_response_is_different() {
2486 let app = Router::new().route(&"/json", get(route_get_json));
2487 let server = TestServer::new(app).unwrap();
2488
2489 server
2490 .get(&"/json")
2491 .await
2492 .assert_json_contains(&ExampleResponse {
2493 time: 1234,
2494 name: "Julia".to_string(),
2495 age: 25,
2496 });
2497 }
2498
2499 #[tokio::test]
2500 #[should_panic]
2501 async fn it_should_panic_if_response_is_form() {
2502 let app = Router::new().route(&"/form", get(route_get_form));
2503 let server = TestServer::new(app).unwrap();
2504
2505 server.get(&"/form").await.assert_json_contains(&json!({
2506 "name": "Joe",
2507 "age": 20,
2508 }));
2509 }
2510
2511 #[tokio::test]
2513 async fn it_should_propagate_contains_to_sub_objects() {
2514 let json_result = json!({ "a": {"prop1": "value1"} }).to_string();
2515 let app = Router::new().route(&"/json", get(|| async { json_result }));
2516
2517 let server = TestServer::new(app).unwrap();
2518 let response = server.get("/json").await;
2519
2520 response.assert_json_contains(&json!({ "a": {} }));
2521 }
2522}
2523
2524#[cfg(test)]
2525mod test_assert_json_from_file {
2526 use crate::TestServer;
2527 use axum::Form;
2528 use axum::Json;
2529 use axum::routing::Router;
2530 use axum::routing::get;
2531 use serde::Deserialize;
2532 use serde::Serialize;
2533 use serde_json::json;
2534
2535 #[tokio::test]
2536 async fn it_should_match_json_from_file() {
2537 let app = Router::new().route(
2538 &"/json",
2539 get(|| async {
2540 Json(json!(
2541 {
2542 "name": "Joe",
2543 "age": 20,
2544 }
2545 ))
2546 }),
2547 );
2548 let server = TestServer::new(app).unwrap();
2549
2550 server
2551 .get(&"/json")
2552 .await
2553 .assert_json_from_file("files/example.json");
2554 }
2555
2556 #[tokio::test]
2557 #[should_panic]
2558 async fn it_should_panic_when_not_match_the_file() {
2559 let app = Router::new().route(
2560 &"/json",
2561 get(|| async {
2562 Json(json!(
2563 {
2564 "name": "Julia",
2565 "age": 25,
2566 }
2567 ))
2568 }),
2569 );
2570 let server = TestServer::new(app).unwrap();
2571
2572 server
2573 .get(&"/json")
2574 .await
2575 .assert_json_from_file("files/example.json");
2576 }
2577
2578 #[tokio::test]
2579 #[should_panic]
2580 async fn it_should_panic_when_content_type_does_not_match() {
2581 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2582 struct ExampleResponse {
2583 name: String,
2584 age: u32,
2585 }
2586
2587 let app = Router::new().route(
2588 &"/form",
2589 get(|| async {
2590 Form(ExampleResponse {
2591 name: "Joe".to_string(),
2592 age: 20,
2593 })
2594 }),
2595 );
2596 let server = TestServer::new(app).unwrap();
2597
2598 server
2599 .get(&"/form")
2600 .await
2601 .assert_json_from_file("files/example.json");
2602 }
2603}
2604
2605#[cfg(feature = "yaml")]
2606#[cfg(test)]
2607mod test_assert_yaml {
2608 use crate::TestServer;
2609 use axum::Form;
2610 use axum::Router;
2611 use axum::routing::get;
2612 use axum_yaml::Yaml;
2613 use serde::Deserialize;
2614 use serde::Serialize;
2615
2616 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2617 struct ExampleResponse {
2618 name: String,
2619 age: u32,
2620 }
2621
2622 async fn route_get_form() -> Form<ExampleResponse> {
2623 Form(ExampleResponse {
2624 name: "Joe".to_string(),
2625 age: 20,
2626 })
2627 }
2628
2629 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2630 Yaml(ExampleResponse {
2631 name: "Joe".to_string(),
2632 age: 20,
2633 })
2634 }
2635
2636 #[tokio::test]
2637 async fn it_should_match_yaml_returned() {
2638 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2639
2640 let server = TestServer::new(app).unwrap();
2641
2642 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2643 name: "Joe".to_string(),
2644 age: 20,
2645 });
2646 }
2647
2648 #[tokio::test]
2649 #[should_panic]
2650 async fn it_should_panic_if_response_is_different() {
2651 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2652
2653 let server = TestServer::new(app).unwrap();
2654
2655 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2656 name: "Julia".to_string(),
2657 age: 25,
2658 });
2659 }
2660
2661 #[tokio::test]
2662 #[should_panic]
2663 async fn it_should_panic_if_response_is_form() {
2664 let app = Router::new().route(&"/form", get(route_get_form));
2665
2666 let server = TestServer::new(app).unwrap();
2667
2668 server.get(&"/form").await.assert_yaml(&ExampleResponse {
2669 name: "Joe".to_string(),
2670 age: 20,
2671 });
2672 }
2673}
2674
2675#[cfg(feature = "yaml")]
2676#[cfg(test)]
2677mod test_assert_yaml_from_file {
2678 use crate::TestServer;
2679 use axum::Form;
2680 use axum::routing::Router;
2681 use axum::routing::get;
2682 use axum_yaml::Yaml;
2683 use serde::Deserialize;
2684 use serde::Serialize;
2685 use serde_json::json;
2686
2687 #[tokio::test]
2688 async fn it_should_match_yaml_from_file() {
2689 let app = Router::new().route(
2690 &"/yaml",
2691 get(|| async {
2692 Yaml(json!(
2693 {
2694 "name": "Joe",
2695 "age": 20,
2696 }
2697 ))
2698 }),
2699 );
2700 let server = TestServer::new(app).unwrap();
2701
2702 server
2703 .get(&"/yaml")
2704 .await
2705 .assert_yaml_from_file("files/example.yaml");
2706 }
2707
2708 #[tokio::test]
2709 #[should_panic]
2710 async fn it_should_panic_when_not_match_the_file() {
2711 let app = Router::new().route(
2712 &"/yaml",
2713 get(|| async {
2714 Yaml(json!(
2715 {
2716 "name": "Julia",
2717 "age": 25,
2718 }
2719 ))
2720 }),
2721 );
2722 let server = TestServer::new(app).unwrap();
2723
2724 server
2725 .get(&"/yaml")
2726 .await
2727 .assert_yaml_from_file("files/example.yaml");
2728 }
2729
2730 #[tokio::test]
2731 #[should_panic]
2732 async fn it_should_panic_when_content_type_does_not_match() {
2733 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2734 struct ExampleResponse {
2735 name: String,
2736 age: u32,
2737 }
2738
2739 let app = Router::new().route(
2740 &"/form",
2741 get(|| async {
2742 Form(ExampleResponse {
2743 name: "Joe".to_string(),
2744 age: 20,
2745 })
2746 }),
2747 );
2748 let server = TestServer::new(app).unwrap();
2749
2750 server
2751 .get(&"/form")
2752 .await
2753 .assert_yaml_from_file("files/example.yaml");
2754 }
2755}
2756
2757#[cfg(test)]
2758mod test_assert_form {
2759 use crate::TestServer;
2760 use axum::Form;
2761 use axum::Json;
2762 use axum::Router;
2763 use axum::routing::get;
2764 use serde::Deserialize;
2765 use serde::Serialize;
2766
2767 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2768 struct ExampleResponse {
2769 name: String,
2770 age: u32,
2771 }
2772
2773 async fn route_get_form() -> Form<ExampleResponse> {
2774 Form(ExampleResponse {
2775 name: "Joe".to_string(),
2776 age: 20,
2777 })
2778 }
2779
2780 async fn route_get_json() -> Json<ExampleResponse> {
2781 Json(ExampleResponse {
2782 name: "Joe".to_string(),
2783 age: 20,
2784 })
2785 }
2786
2787 #[tokio::test]
2788 async fn it_should_match_form_returned() {
2789 let app = Router::new().route(&"/form", get(route_get_form));
2790
2791 let server = TestServer::new(app).unwrap();
2792
2793 server.get(&"/form").await.assert_form(&ExampleResponse {
2794 name: "Joe".to_string(),
2795 age: 20,
2796 });
2797 }
2798
2799 #[tokio::test]
2800 #[should_panic]
2801 async fn it_should_panic_if_response_is_different() {
2802 let app = Router::new().route(&"/form", get(route_get_form));
2803
2804 let server = TestServer::new(app).unwrap();
2805
2806 server.get(&"/form").await.assert_form(&ExampleResponse {
2807 name: "Julia".to_string(),
2808 age: 25,
2809 });
2810 }
2811
2812 #[tokio::test]
2813 #[should_panic]
2814 async fn it_should_panic_if_response_is_json() {
2815 let app = Router::new().route(&"/json", get(route_get_json));
2816
2817 let server = TestServer::new(app).unwrap();
2818
2819 server.get(&"/json").await.assert_form(&ExampleResponse {
2820 name: "Joe".to_string(),
2821 age: 20,
2822 });
2823 }
2824}
2825
2826#[cfg(test)]
2827mod test_text {
2828 use crate::TestServer;
2829 use axum::Router;
2830 use axum::routing::get;
2831
2832 #[tokio::test]
2833 async fn it_should_deserialize_into_text() {
2834 async fn route_get_text() -> String {
2835 "hello!".to_string()
2836 }
2837
2838 let app = Router::new().route(&"/text", get(route_get_text));
2839
2840 let server = TestServer::new(app).unwrap();
2841
2842 let response = server.get(&"/text").await.text();
2843
2844 assert_eq!(response, "hello!");
2845 }
2846}
2847
2848#[cfg(feature = "ws")]
2849#[cfg(test)]
2850mod test_into_websocket {
2851 use crate::TestServer;
2852
2853 use axum::Router;
2854 use axum::extract::WebSocketUpgrade;
2855 use axum::extract::ws::WebSocket;
2856 use axum::response::Response;
2857 use axum::routing::get;
2858
2859 fn new_test_router() -> Router {
2860 pub async fn route_get_websocket(ws: WebSocketUpgrade) -> Response {
2861 async fn handle_ping_pong(mut socket: WebSocket) {
2862 while let Some(_) = socket.recv().await {
2863 }
2865 }
2866
2867 ws.on_upgrade(move |socket| handle_ping_pong(socket))
2868 }
2869
2870 let app = Router::new().route(&"/ws", get(route_get_websocket));
2871
2872 app
2873 }
2874
2875 #[tokio::test]
2876 async fn it_should_upgrade_on_http_transport() {
2877 let router = new_test_router();
2878 let server = TestServer::builder()
2879 .http_transport()
2880 .build(router)
2881 .unwrap();
2882
2883 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2884
2885 assert!(true);
2886 }
2887
2888 #[tokio::test]
2889 #[should_panic]
2890 async fn it_should_fail_to_upgrade_on_mock_transport() {
2891 let router = new_test_router();
2892 let server = TestServer::builder()
2893 .mock_transport()
2894 .build(router)
2895 .unwrap();
2896
2897 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2898 }
2899}