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_no_content(&self) {
1217 self.assert_status(StatusCode::NO_CONTENT)
1218 }
1219
1220 #[track_caller]
1222 pub fn assert_status_see_other(&self) {
1223 self.assert_status(StatusCode::SEE_OTHER)
1224 }
1225
1226 #[track_caller]
1228 pub fn assert_status_bad_request(&self) {
1229 self.assert_status(StatusCode::BAD_REQUEST)
1230 }
1231
1232 #[track_caller]
1234 pub fn assert_status_not_found(&self) {
1235 self.assert_status(StatusCode::NOT_FOUND)
1236 }
1237
1238 #[track_caller]
1240 pub fn assert_status_unauthorized(&self) {
1241 self.assert_status(StatusCode::UNAUTHORIZED)
1242 }
1243
1244 #[track_caller]
1246 pub fn assert_status_forbidden(&self) {
1247 self.assert_status(StatusCode::FORBIDDEN)
1248 }
1249
1250 pub fn assert_status_conflict(&self) {
1252 self.assert_status(StatusCode::CONFLICT)
1253 }
1254
1255 #[track_caller]
1259 pub fn assert_status_payload_too_large(&self) {
1260 self.assert_status(StatusCode::PAYLOAD_TOO_LARGE)
1261 }
1262
1263 #[track_caller]
1265 pub fn assert_status_unprocessable_entity(&self) {
1266 self.assert_status(StatusCode::UNPROCESSABLE_ENTITY)
1267 }
1268
1269 #[track_caller]
1271 pub fn assert_status_too_many_requests(&self) {
1272 self.assert_status(StatusCode::TOO_MANY_REQUESTS)
1273 }
1274
1275 #[track_caller]
1280 pub fn assert_status_switching_protocols(&self) {
1281 self.assert_status(StatusCode::SWITCHING_PROTOCOLS)
1282 }
1283
1284 #[track_caller]
1286 pub fn assert_status_internal_server_error(&self) {
1287 self.assert_status(StatusCode::INTERNAL_SERVER_ERROR)
1288 }
1289
1290 #[track_caller]
1292 pub fn assert_status_service_unavailable(&self) {
1293 self.assert_status(StatusCode::SERVICE_UNAVAILABLE)
1294 }
1295
1296 fn debug_request_format(&self) -> RequestPathFormatter<'_> {
1297 RequestPathFormatter::new(&self.method, self.full_request_url.as_str(), None)
1298 }
1299}
1300
1301impl From<TestResponse> for Bytes {
1302 fn from(response: TestResponse) -> Self {
1303 response.into_bytes()
1304 }
1305}
1306
1307#[cfg(test)]
1308mod test_assert_header {
1309 use crate::TestServer;
1310 use axum::http::HeaderMap;
1311 use axum::routing::get;
1312 use axum::Router;
1313
1314 async fn route_get_header() -> HeaderMap {
1315 let mut headers = HeaderMap::new();
1316 headers.insert("x-my-custom-header", "content".parse().unwrap());
1317 headers
1318 }
1319
1320 #[tokio::test]
1321 async fn it_should_not_panic_if_contains_header_and_content_matches() {
1322 let router = Router::new().route(&"/header", get(route_get_header));
1323
1324 let server = TestServer::new(router).unwrap();
1325
1326 server
1327 .get(&"/header")
1328 .await
1329 .assert_header("x-my-custom-header", "content");
1330 }
1331
1332 #[tokio::test]
1333 #[should_panic]
1334 async fn it_should_panic_if_contains_header_and_content_does_not_match() {
1335 let router = Router::new().route(&"/header", get(route_get_header));
1336
1337 let server = TestServer::new(router).unwrap();
1338
1339 server
1340 .get(&"/header")
1341 .await
1342 .assert_header("x-my-custom-header", "different-content");
1343 }
1344
1345 #[tokio::test]
1346 #[should_panic]
1347 async fn it_should_panic_if_not_contains_header() {
1348 let router = Router::new().route(&"/header", get(route_get_header));
1349
1350 let server = TestServer::new(router).unwrap();
1351
1352 server
1353 .get(&"/header")
1354 .await
1355 .assert_header("x-custom-header-not-found", "content");
1356 }
1357}
1358
1359#[cfg(test)]
1360mod test_assert_contains_header {
1361 use crate::TestServer;
1362 use axum::http::HeaderMap;
1363 use axum::routing::get;
1364 use axum::Router;
1365
1366 async fn route_get_header() -> HeaderMap {
1367 let mut headers = HeaderMap::new();
1368 headers.insert("x-my-custom-header", "content".parse().unwrap());
1369 headers
1370 }
1371
1372 #[tokio::test]
1373 async fn it_should_not_panic_if_contains_header() {
1374 let router = Router::new().route(&"/header", get(route_get_header));
1375
1376 let server = TestServer::new(router).unwrap();
1377
1378 server
1379 .get(&"/header")
1380 .await
1381 .assert_contains_header("x-my-custom-header");
1382 }
1383
1384 #[tokio::test]
1385 #[should_panic]
1386 async fn it_should_panic_if_not_contains_header() {
1387 let router = Router::new().route(&"/header", get(route_get_header));
1388
1389 let server = TestServer::new(router).unwrap();
1390
1391 server
1392 .get(&"/header")
1393 .await
1394 .assert_contains_header("x-custom-header-not-found");
1395 }
1396}
1397
1398#[cfg(test)]
1399mod test_assert_success {
1400 use crate::TestServer;
1401 use axum::routing::get;
1402 use axum::Router;
1403 use http::StatusCode;
1404
1405 pub async fn route_get_pass() -> StatusCode {
1406 StatusCode::OK
1407 }
1408
1409 pub async fn route_get_fail() -> StatusCode {
1410 StatusCode::SERVICE_UNAVAILABLE
1411 }
1412
1413 #[tokio::test]
1414 async fn it_should_pass_when_200() {
1415 let router = Router::new()
1416 .route(&"/pass", get(route_get_pass))
1417 .route(&"/fail", get(route_get_fail));
1418
1419 let server = TestServer::new(router).unwrap();
1420
1421 let response = server.get(&"/pass").await;
1422
1423 response.assert_status_success()
1424 }
1425
1426 #[tokio::test]
1427 #[should_panic]
1428 async fn it_should_panic_when_not_200() {
1429 let router = Router::new()
1430 .route(&"/pass", get(route_get_pass))
1431 .route(&"/fail", get(route_get_fail));
1432
1433 let server = TestServer::new(router).unwrap();
1434
1435 let response = server.get(&"/fail").expect_failure().await;
1436
1437 response.assert_status_success()
1438 }
1439}
1440
1441#[cfg(test)]
1442mod test_assert_failure {
1443 use crate::TestServer;
1444 use axum::routing::get;
1445 use axum::Router;
1446 use http::StatusCode;
1447
1448 pub async fn route_get_pass() -> StatusCode {
1449 StatusCode::OK
1450 }
1451
1452 pub async fn route_get_fail() -> StatusCode {
1453 StatusCode::SERVICE_UNAVAILABLE
1454 }
1455
1456 #[tokio::test]
1457 async fn it_should_pass_when_not_200() {
1458 let router = Router::new()
1459 .route(&"/pass", get(route_get_pass))
1460 .route(&"/fail", get(route_get_fail));
1461
1462 let server = TestServer::new(router).unwrap();
1463 let response = server.get(&"/fail").expect_failure().await;
1464
1465 response.assert_status_failure()
1466 }
1467
1468 #[tokio::test]
1469 #[should_panic]
1470 async fn it_should_panic_when_200() {
1471 let router = Router::new()
1472 .route(&"/pass", get(route_get_pass))
1473 .route(&"/fail", get(route_get_fail));
1474
1475 let server = TestServer::new(router).unwrap();
1476 let response = server.get(&"/pass").await;
1477
1478 response.assert_status_failure()
1479 }
1480}
1481
1482#[cfg(test)]
1483mod test_assert_status {
1484 use crate::TestServer;
1485 use axum::routing::get;
1486 use axum::Router;
1487 use http::StatusCode;
1488
1489 pub async fn route_get_ok() -> StatusCode {
1490 StatusCode::OK
1491 }
1492
1493 #[tokio::test]
1494 async fn it_should_pass_if_given_right_status_code() {
1495 let router = Router::new().route(&"/ok", get(route_get_ok));
1496 let server = TestServer::new(router).unwrap();
1497
1498 server.get(&"/ok").await.assert_status(StatusCode::OK);
1499 }
1500
1501 #[tokio::test]
1502 #[should_panic]
1503 async fn it_should_panic_when_status_code_does_not_match() {
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::ACCEPTED);
1508 }
1509}
1510
1511#[cfg(test)]
1512mod test_assert_not_status {
1513 use crate::TestServer;
1514 use axum::routing::get;
1515 use axum::Router;
1516 use http::StatusCode;
1517
1518 pub async fn route_get_ok() -> StatusCode {
1519 StatusCode::OK
1520 }
1521
1522 #[tokio::test]
1523 async fn it_should_pass_if_status_code_does_not_match() {
1524 let router = Router::new().route(&"/ok", get(route_get_ok));
1525 let server = TestServer::new(router).unwrap();
1526
1527 server
1528 .get(&"/ok")
1529 .await
1530 .assert_not_status(StatusCode::ACCEPTED);
1531 }
1532
1533 #[tokio::test]
1534 #[should_panic]
1535 async fn it_should_panic_if_status_code_matches() {
1536 let router = Router::new().route(&"/ok", get(route_get_ok));
1537 let server = TestServer::new(router).unwrap();
1538
1539 server.get(&"/ok").await.assert_not_status(StatusCode::OK);
1540 }
1541}
1542
1543#[cfg(test)]
1544mod test_assert_status_in_range {
1545 use crate::TestServer;
1546 use axum::routing::get;
1547 use axum::routing::Router;
1548 use http::StatusCode;
1549 use std::ops::RangeFull;
1550
1551 #[tokio::test]
1552 async fn it_should_be_true_when_within_int_range() {
1553 let app = Router::new().route(
1554 &"/status",
1555 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1556 );
1557
1558 TestServer::new(app)
1559 .unwrap()
1560 .get(&"/status")
1561 .await
1562 .assert_status_in_range(200..299);
1563 }
1564
1565 #[tokio::test]
1566 async fn it_should_be_true_when_within_status_code_range() {
1567 let app = Router::new().route(
1568 &"/status",
1569 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1570 );
1571
1572 TestServer::new(app)
1573 .unwrap()
1574 .get(&"/status")
1575 .await
1576 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1577 }
1578
1579 #[tokio::test]
1580 #[should_panic]
1581 async fn it_should_be_false_when_outside_int_range() {
1582 let app = Router::new().route(
1583 &"/status",
1584 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1585 );
1586
1587 TestServer::new(app)
1588 .unwrap()
1589 .get(&"/status")
1590 .await
1591 .assert_status_in_range(200..299);
1592 }
1593
1594 #[tokio::test]
1595 #[should_panic]
1596 async fn it_should_be_false_when_outside_status_code_range() {
1597 let app = Router::new().route(
1598 &"/status",
1599 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1600 );
1601
1602 TestServer::new(app)
1603 .unwrap()
1604 .get(&"/status")
1605 .await
1606 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1607 }
1608
1609 #[tokio::test]
1610 async fn it_should_be_true_when_within_inclusive_range() {
1611 let app = Router::new().route(
1612 &"/status",
1613 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1614 );
1615
1616 TestServer::new(app)
1617 .unwrap()
1618 .get(&"/status")
1619 .await
1620 .assert_status_in_range(200..=299);
1621 }
1622
1623 #[tokio::test]
1624 #[should_panic]
1625 async fn it_should_be_false_when_outside_inclusive_range() {
1626 let app = Router::new().route(
1627 &"/status",
1628 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1629 );
1630
1631 TestServer::new(app)
1632 .unwrap()
1633 .get(&"/status")
1634 .await
1635 .assert_status_in_range(200..=299);
1636 }
1637
1638 #[tokio::test]
1639 async fn it_should_be_true_when_within_to_range() {
1640 let app = Router::new().route(
1641 &"/status",
1642 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1643 );
1644
1645 TestServer::new(app)
1646 .unwrap()
1647 .get(&"/status")
1648 .await
1649 .assert_status_in_range(..299);
1650 }
1651
1652 #[tokio::test]
1653 #[should_panic]
1654 async fn it_should_be_false_when_outside_to_range() {
1655 let app = Router::new().route(
1656 &"/status",
1657 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1658 );
1659
1660 TestServer::new(app)
1661 .unwrap()
1662 .get(&"/status")
1663 .await
1664 .assert_status_in_range(..299);
1665 }
1666
1667 #[tokio::test]
1668 async fn it_should_be_true_when_within_to_inclusive_range() {
1669 let app = Router::new().route(
1670 &"/status",
1671 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1672 );
1673
1674 TestServer::new(app)
1675 .unwrap()
1676 .get(&"/status")
1677 .await
1678 .assert_status_in_range(..=299);
1679 }
1680
1681 #[tokio::test]
1682 #[should_panic]
1683 async fn it_should_be_false_when_outside_to_inclusive_range() {
1684 let app = Router::new().route(
1685 &"/status",
1686 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1687 );
1688
1689 TestServer::new(app)
1690 .unwrap()
1691 .get(&"/status")
1692 .await
1693 .assert_status_in_range(..=299);
1694 }
1695
1696 #[tokio::test]
1697 async fn it_should_be_true_when_within_from_range() {
1698 let app = Router::new().route(
1699 &"/status",
1700 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1701 );
1702
1703 TestServer::new(app)
1704 .unwrap()
1705 .get(&"/status")
1706 .await
1707 .assert_status_in_range(200..);
1708 }
1709
1710 #[tokio::test]
1711 #[should_panic]
1712 async fn it_should_be_false_when_outside_from_range() {
1713 let app = Router::new().route(
1714 &"/status",
1715 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1716 );
1717
1718 TestServer::new(app)
1719 .unwrap()
1720 .get(&"/status")
1721 .await
1722 .assert_status_in_range(500..);
1723 }
1724
1725 #[tokio::test]
1726 async fn it_should_be_true_for_rull_range() {
1727 let app = Router::new().route(
1728 &"/status",
1729 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1730 );
1731
1732 TestServer::new(app)
1733 .unwrap()
1734 .get(&"/status")
1735 .await
1736 .assert_status_in_range::<RangeFull, StatusCode>(..);
1737 }
1738}
1739
1740#[cfg(test)]
1741mod test_assert_status_not_in_range {
1742 use crate::TestServer;
1743 use axum::routing::get;
1744 use axum::routing::Router;
1745 use http::StatusCode;
1746 use std::ops::RangeFull;
1747
1748 #[tokio::test]
1749 #[should_panic]
1750 async fn it_should_be_false_when_within_int_range() {
1751 let app = Router::new().route(
1752 &"/status",
1753 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1754 );
1755
1756 TestServer::new(app)
1757 .unwrap()
1758 .get(&"/status")
1759 .await
1760 .assert_status_not_in_range(200..299);
1761 }
1762
1763 #[tokio::test]
1764 #[should_panic]
1765 async fn it_should_be_false_when_within_status_code_range() {
1766 let app = Router::new().route(
1767 &"/status",
1768 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1769 );
1770
1771 TestServer::new(app)
1772 .unwrap()
1773 .get(&"/status")
1774 .await
1775 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1776 }
1777
1778 #[tokio::test]
1779 async fn it_should_be_true_when_outside_int_range() {
1780 let app = Router::new().route(
1781 &"/status",
1782 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1783 );
1784
1785 TestServer::new(app)
1786 .unwrap()
1787 .get(&"/status")
1788 .await
1789 .assert_status_not_in_range(200..299);
1790 }
1791
1792 #[tokio::test]
1793 async fn it_should_be_true_when_outside_status_code_range() {
1794 let app = Router::new().route(
1795 &"/status",
1796 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1797 );
1798
1799 TestServer::new(app)
1800 .unwrap()
1801 .get(&"/status")
1802 .await
1803 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1804 }
1805
1806 #[tokio::test]
1807 #[should_panic]
1808 async fn it_should_be_false_when_within_inclusive_range() {
1809 let app = Router::new().route(
1810 &"/status",
1811 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1812 );
1813
1814 TestServer::new(app)
1815 .unwrap()
1816 .get(&"/status")
1817 .await
1818 .assert_status_not_in_range(200..=299);
1819 }
1820
1821 #[tokio::test]
1822 async fn it_should_be_true_when_outside_inclusive_range() {
1823 let app = Router::new().route(
1824 &"/status",
1825 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1826 );
1827
1828 TestServer::new(app)
1829 .unwrap()
1830 .get(&"/status")
1831 .await
1832 .assert_status_not_in_range(200..=299);
1833 }
1834
1835 #[tokio::test]
1836 #[should_panic]
1837 async fn it_should_be_false_when_within_to_range() {
1838 let app = Router::new().route(
1839 &"/status",
1840 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1841 );
1842
1843 TestServer::new(app)
1844 .unwrap()
1845 .get(&"/status")
1846 .await
1847 .assert_status_not_in_range(..299);
1848 }
1849
1850 #[tokio::test]
1851 async fn it_should_be_true_when_outside_to_range() {
1852 let app = Router::new().route(
1853 &"/status",
1854 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1855 );
1856
1857 TestServer::new(app)
1858 .unwrap()
1859 .get(&"/status")
1860 .await
1861 .assert_status_not_in_range(..299);
1862 }
1863
1864 #[tokio::test]
1865 #[should_panic]
1866 async fn it_should_be_false_when_within_to_inclusive_range() {
1867 let app = Router::new().route(
1868 &"/status",
1869 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1870 );
1871
1872 TestServer::new(app)
1873 .unwrap()
1874 .get(&"/status")
1875 .await
1876 .assert_status_not_in_range(..=299);
1877 }
1878
1879 #[tokio::test]
1880 async fn it_should_be_true_when_outside_to_inclusive_range() {
1881 let app = Router::new().route(
1882 &"/status",
1883 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1884 );
1885
1886 TestServer::new(app)
1887 .unwrap()
1888 .get(&"/status")
1889 .await
1890 .assert_status_not_in_range(..=299);
1891 }
1892
1893 #[tokio::test]
1894 #[should_panic]
1895 async fn it_should_be_false_when_within_from_range() {
1896 let app = Router::new().route(
1897 &"/status",
1898 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1899 );
1900
1901 TestServer::new(app)
1902 .unwrap()
1903 .get(&"/status")
1904 .await
1905 .assert_status_not_in_range(200..);
1906 }
1907
1908 #[tokio::test]
1909 async fn it_should_be_true_when_outside_from_range() {
1910 let app = Router::new().route(
1911 &"/status",
1912 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1913 );
1914
1915 TestServer::new(app)
1916 .unwrap()
1917 .get(&"/status")
1918 .await
1919 .assert_status_not_in_range(500..);
1920 }
1921
1922 #[tokio::test]
1923 #[should_panic]
1924 async fn it_should_be_false_for_rull_range() {
1925 let app = Router::new().route(
1926 &"/status",
1927 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1928 );
1929
1930 TestServer::new(app)
1931 .unwrap()
1932 .get(&"/status")
1933 .await
1934 .assert_status_not_in_range::<RangeFull, StatusCode>(..);
1935 }
1936}
1937
1938#[cfg(test)]
1939mod test_into_bytes {
1940 use crate::TestServer;
1941 use axum::routing::get;
1942 use axum::Json;
1943 use axum::Router;
1944 use serde_json::json;
1945 use serde_json::Value;
1946
1947 async fn route_get_json() -> Json<Value> {
1948 Json(json!({
1949 "message": "it works?"
1950 }))
1951 }
1952
1953 #[tokio::test]
1954 async fn it_should_deserialize_into_json() {
1955 let app = Router::new().route(&"/json", get(route_get_json));
1956
1957 let server = TestServer::new(app).unwrap();
1958
1959 let bytes = server.get(&"/json").await.into_bytes();
1960 let text = String::from_utf8_lossy(&bytes);
1961
1962 assert_eq!(text, r#"{"message":"it works?"}"#);
1963 }
1964}
1965
1966#[cfg(test)]
1967mod test_content_type {
1968 use crate::TestServer;
1969 use axum::routing::get;
1970 use axum::Json;
1971 use axum::Router;
1972 use serde::Deserialize;
1973 use serde::Serialize;
1974
1975 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1976 struct ExampleResponse {
1977 name: String,
1978 age: u32,
1979 }
1980
1981 #[tokio::test]
1982 async fn it_should_retrieve_json_content_type_for_json() {
1983 let app = Router::new().route(
1984 &"/json",
1985 get(|| async {
1986 Json(ExampleResponse {
1987 name: "Joe".to_string(),
1988 age: 20,
1989 })
1990 }),
1991 );
1992
1993 let server = TestServer::new(app).unwrap();
1994
1995 let content_type = server.get(&"/json").await.content_type();
1996 assert_eq!(content_type, "application/json");
1997 }
1998
1999 #[cfg(feature = "yaml")]
2000 #[tokio::test]
2001 async fn it_should_retrieve_yaml_content_type_for_yaml() {
2002 use axum_yaml::Yaml;
2003
2004 let app = Router::new().route(
2005 &"/yaml",
2006 get(|| async {
2007 Yaml(ExampleResponse {
2008 name: "Joe".to_string(),
2009 age: 20,
2010 })
2011 }),
2012 );
2013
2014 let server = TestServer::new(app).unwrap();
2015
2016 let content_type = server.get(&"/yaml").await.content_type();
2017 assert_eq!(content_type, "application/yaml");
2018 }
2019}
2020
2021#[cfg(test)]
2022mod test_json {
2023 use crate::TestServer;
2024 use axum::routing::get;
2025 use axum::Json;
2026 use axum::Router;
2027 use serde::Deserialize;
2028 use serde::Serialize;
2029
2030 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2031 struct ExampleResponse {
2032 name: String,
2033 age: u32,
2034 }
2035
2036 async fn route_get_json() -> Json<ExampleResponse> {
2037 Json(ExampleResponse {
2038 name: "Joe".to_string(),
2039 age: 20,
2040 })
2041 }
2042
2043 #[tokio::test]
2044 async fn it_should_deserialize_into_json() {
2045 let app = Router::new().route(&"/json", get(route_get_json));
2046
2047 let server = TestServer::new(app).unwrap();
2048
2049 let response = server.get(&"/json").await.json::<ExampleResponse>();
2050
2051 assert_eq!(
2052 response,
2053 ExampleResponse {
2054 name: "Joe".to_string(),
2055 age: 20,
2056 }
2057 );
2058 }
2059}
2060
2061#[cfg(feature = "yaml")]
2062#[cfg(test)]
2063mod test_yaml {
2064 use crate::TestServer;
2065 use axum::routing::get;
2066 use axum::Router;
2067 use axum_yaml::Yaml;
2068 use serde::Deserialize;
2069 use serde::Serialize;
2070
2071 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2072 struct ExampleResponse {
2073 name: String,
2074 age: u32,
2075 }
2076
2077 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2078 Yaml(ExampleResponse {
2079 name: "Joe".to_string(),
2080 age: 20,
2081 })
2082 }
2083
2084 #[tokio::test]
2085 async fn it_should_deserialize_into_yaml() {
2086 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2087
2088 let server = TestServer::new(app).unwrap();
2089
2090 let response = server.get(&"/yaml").await.yaml::<ExampleResponse>();
2091
2092 assert_eq!(
2093 response,
2094 ExampleResponse {
2095 name: "Joe".to_string(),
2096 age: 20,
2097 }
2098 );
2099 }
2100}
2101
2102#[cfg(feature = "msgpack")]
2103#[cfg(test)]
2104mod test_msgpack {
2105 use crate::TestServer;
2106 use axum::routing::get;
2107 use axum::Router;
2108 use axum_msgpack::MsgPack;
2109 use serde::Deserialize;
2110 use serde::Serialize;
2111
2112 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2113 struct ExampleResponse {
2114 name: String,
2115 age: u32,
2116 }
2117
2118 async fn route_get_msgpack() -> MsgPack<ExampleResponse> {
2119 MsgPack(ExampleResponse {
2120 name: "Joe".to_string(),
2121 age: 20,
2122 })
2123 }
2124
2125 #[tokio::test]
2126 async fn it_should_deserialize_into_msgpack() {
2127 let app = Router::new().route(&"/msgpack", get(route_get_msgpack));
2128
2129 let server = TestServer::new(app).unwrap();
2130
2131 let response = server.get(&"/msgpack").await.msgpack::<ExampleResponse>();
2132
2133 assert_eq!(
2134 response,
2135 ExampleResponse {
2136 name: "Joe".to_string(),
2137 age: 20,
2138 }
2139 );
2140 }
2141}
2142
2143#[cfg(test)]
2144mod test_form {
2145 use crate::TestServer;
2146 use axum::routing::get;
2147 use axum::Form;
2148 use axum::Router;
2149 use serde::Deserialize;
2150 use serde::Serialize;
2151
2152 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2153 struct ExampleResponse {
2154 name: String,
2155 age: u32,
2156 }
2157
2158 async fn route_get_form() -> Form<ExampleResponse> {
2159 Form(ExampleResponse {
2160 name: "Joe".to_string(),
2161 age: 20,
2162 })
2163 }
2164
2165 #[tokio::test]
2166 async fn it_should_deserialize_into_form() {
2167 let app = Router::new().route(&"/form", get(route_get_form));
2168
2169 let server = TestServer::new(app).unwrap();
2170
2171 let response = server.get(&"/form").await.form::<ExampleResponse>();
2172
2173 assert_eq!(
2174 response,
2175 ExampleResponse {
2176 name: "Joe".to_string(),
2177 age: 20,
2178 }
2179 );
2180 }
2181}
2182
2183#[cfg(test)]
2184mod test_from {
2185 use crate::TestServer;
2186 use axum::routing::get;
2187 use axum::Router;
2188 use bytes::Bytes;
2189
2190 #[tokio::test]
2191 async fn it_should_turn_into_response_bytes() {
2192 let app = Router::new().route(&"/text", get(|| async { "This is some example text" }));
2193 let server = TestServer::new(app).unwrap();
2194
2195 let response = server.get(&"/text").await;
2196 let bytes: Bytes = response.into();
2197 let text = String::from_utf8_lossy(&bytes);
2198 assert_eq!(text, "This is some example text");
2199 }
2200}
2201
2202#[cfg(test)]
2203mod test_assert_text {
2204 use crate::TestServer;
2205 use axum::routing::get;
2206 use axum::Router;
2207
2208 fn new_test_server() -> TestServer {
2209 async fn route_get_text() -> &'static str {
2210 "This is some example text"
2211 }
2212
2213 let app = Router::new().route(&"/text", get(route_get_text));
2214 TestServer::new(app).unwrap()
2215 }
2216
2217 #[tokio::test]
2218 async fn it_should_match_whole_text() {
2219 let server = new_test_server();
2220
2221 server
2222 .get(&"/text")
2223 .await
2224 .assert_text("This is some example text");
2225 }
2226
2227 #[tokio::test]
2228 #[should_panic]
2229 async fn it_should_not_match_partial_text() {
2230 let server = new_test_server();
2231
2232 server.get(&"/text").await.assert_text("some example");
2233 }
2234
2235 #[tokio::test]
2236 #[should_panic]
2237 async fn it_should_not_match_different_text() {
2238 let server = new_test_server();
2239
2240 server.get(&"/text").await.assert_text("🦊");
2241 }
2242}
2243
2244#[cfg(test)]
2245mod test_assert_text_contains {
2246 use crate::TestServer;
2247 use axum::routing::get;
2248 use axum::Router;
2249
2250 fn new_test_server() -> TestServer {
2251 async fn route_get_text() -> &'static str {
2252 "This is some example text"
2253 }
2254
2255 let app = Router::new().route(&"/text", get(route_get_text));
2256 TestServer::new(app).unwrap()
2257 }
2258
2259 #[tokio::test]
2260 async fn it_should_match_whole_text() {
2261 let server = new_test_server();
2262
2263 server
2264 .get(&"/text")
2265 .await
2266 .assert_text_contains("This is some example text");
2267 }
2268
2269 #[tokio::test]
2270 async fn it_should_match_partial_text() {
2271 let server = new_test_server();
2272
2273 server
2274 .get(&"/text")
2275 .await
2276 .assert_text_contains("some example");
2277 }
2278
2279 #[tokio::test]
2280 #[should_panic]
2281 async fn it_should_not_match_different_text() {
2282 let server = new_test_server();
2283
2284 server.get(&"/text").await.assert_text_contains("🦊");
2285 }
2286}
2287
2288#[cfg(test)]
2289mod test_assert_text_from_file {
2290 use crate::TestServer;
2291 use axum::routing::get;
2292 use axum::routing::Router;
2293
2294 #[tokio::test]
2295 async fn it_should_match_from_file() {
2296 let app = Router::new().route(&"/text", get(|| async { "hello!" }));
2297 let server = TestServer::new(app).unwrap();
2298
2299 server
2300 .get(&"/text")
2301 .await
2302 .assert_text_from_file("files/example.txt");
2303 }
2304
2305 #[tokio::test]
2306 #[should_panic]
2307 async fn it_should_panic_when_not_match_the_file() {
2308 let app = Router::new().route(&"/text", get(|| async { "🦊" }));
2309 let server = TestServer::new(app).unwrap();
2310
2311 server
2312 .get(&"/text")
2313 .await
2314 .assert_text_from_file("files/example.txt");
2315 }
2316}
2317
2318#[cfg(test)]
2319mod test_assert_json {
2320 use crate::expect_json::expect_core::Context;
2321 use crate::expect_json::expect_core::ExpectOp;
2322 use crate::expect_json::expect_core::ExpectOpResult;
2323 use crate::TestServer;
2324 use ::expect_json::expect_core::expect_op;
2326 use axum::routing::get;
2327 use axum::Form;
2328 use axum::Json;
2329 use axum::Router;
2330 use serde::Deserialize;
2331 use serde::Serialize;
2332 use serde_json::json;
2333
2334 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2335 struct ExampleResponse {
2336 name: String,
2337 age: u32,
2338 }
2339
2340 async fn route_get_form() -> Form<ExampleResponse> {
2341 Form(ExampleResponse {
2342 name: "Joe".to_string(),
2343 age: 20,
2344 })
2345 }
2346
2347 async fn route_get_json() -> Json<ExampleResponse> {
2348 Json(ExampleResponse {
2349 name: "Joe".to_string(),
2350 age: 20,
2351 })
2352 }
2353
2354 #[tokio::test]
2355 async fn it_should_match_json_returned() {
2356 let app = Router::new().route(&"/json", get(route_get_json));
2357
2358 let server = TestServer::new(app).unwrap();
2359
2360 server.get(&"/json").await.assert_json(&ExampleResponse {
2361 name: "Joe".to_string(),
2362 age: 20,
2363 });
2364 }
2365
2366 #[tokio::test]
2367 #[should_panic]
2368 async fn it_should_panic_if_response_is_different() {
2369 let app = Router::new().route(&"/json", get(route_get_json));
2370
2371 let server = TestServer::new(app).unwrap();
2372
2373 server.get(&"/json").await.assert_json(&ExampleResponse {
2374 name: "Julia".to_string(),
2375 age: 25,
2376 });
2377 }
2378
2379 #[tokio::test]
2380 #[should_panic]
2381 async fn it_should_panic_if_response_is_form() {
2382 let app = Router::new().route(&"/form", get(route_get_form));
2383
2384 let server = TestServer::new(app).unwrap();
2385
2386 server.get(&"/form").await.assert_json(&ExampleResponse {
2387 name: "Joe".to_string(),
2388 age: 20,
2389 });
2390 }
2391
2392 #[tokio::test]
2393 async fn it_should_work_with_custom_expect_op() {
2394 #[expect_op]
2395 #[derive(Clone, Debug)]
2396 struct ExpectStrMinLen {
2397 min: usize,
2398 }
2399
2400 impl ExpectOp for ExpectStrMinLen {
2401 fn on_string(&self, _context: &mut Context<'_>, received: &str) -> ExpectOpResult<()> {
2402 if received.len() < self.min {
2403 panic!("String is too short, received: {received}");
2404 }
2405
2406 Ok(())
2407 }
2408 }
2409
2410 let app = Router::new().route(&"/json", get(route_get_json));
2411 let server = TestServer::new(app).unwrap();
2412
2413 server.get(&"/json").await.assert_json(&json!({
2414 "name": ExpectStrMinLen { min: 3 },
2415 "age": 20,
2416 }));
2417 }
2418}
2419
2420#[cfg(test)]
2421mod test_assert_json_contains {
2422 use crate::TestServer;
2423 use axum::routing::get;
2424 use axum::Form;
2425 use axum::Json;
2426 use axum::Router;
2427 use serde::Deserialize;
2428 use serde::Serialize;
2429 use serde_json::json;
2430 use std::time::Instant;
2431
2432 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2433 struct ExampleResponse {
2434 time: u64,
2435 name: String,
2436 age: u32,
2437 }
2438
2439 async fn route_get_form() -> Form<ExampleResponse> {
2440 Form(ExampleResponse {
2441 time: Instant::now().elapsed().as_millis() as u64,
2442 name: "Joe".to_string(),
2443 age: 20,
2444 })
2445 }
2446
2447 async fn route_get_json() -> Json<ExampleResponse> {
2448 Json(ExampleResponse {
2449 time: Instant::now().elapsed().as_millis() as u64,
2450 name: "Joe".to_string(),
2451 age: 20,
2452 })
2453 }
2454
2455 #[tokio::test]
2456 async fn it_should_match_subset_of_json_returned() {
2457 let app = Router::new().route(&"/json", get(route_get_json));
2458 let server = TestServer::new(app).unwrap();
2459
2460 server.get(&"/json").await.assert_json_contains(&json!({
2461 "name": "Joe",
2462 "age": 20,
2463 }));
2464 }
2465
2466 #[tokio::test]
2467 #[should_panic]
2468 async fn it_should_panic_if_response_is_different() {
2469 let app = Router::new().route(&"/json", get(route_get_json));
2470 let server = TestServer::new(app).unwrap();
2471
2472 server
2473 .get(&"/json")
2474 .await
2475 .assert_json_contains(&ExampleResponse {
2476 time: 1234,
2477 name: "Julia".to_string(),
2478 age: 25,
2479 });
2480 }
2481
2482 #[tokio::test]
2483 #[should_panic]
2484 async fn it_should_panic_if_response_is_form() {
2485 let app = Router::new().route(&"/form", get(route_get_form));
2486 let server = TestServer::new(app).unwrap();
2487
2488 server.get(&"/form").await.assert_json_contains(&json!({
2489 "name": "Joe",
2490 "age": 20,
2491 }));
2492 }
2493
2494 #[tokio::test]
2496 async fn it_should_propagate_contains_to_sub_objects() {
2497 let json_result = json!({ "a": {"prop1": "value1"} }).to_string();
2498 let app = Router::new().route(&"/json", get(|| async { json_result }));
2499
2500 let server = TestServer::new(app).unwrap();
2501 let response = server.get("/json").await;
2502
2503 response.assert_json_contains(&json!({ "a": {} }));
2504 }
2505}
2506
2507#[cfg(test)]
2508mod test_assert_json_from_file {
2509 use crate::TestServer;
2510 use axum::routing::get;
2511 use axum::routing::Router;
2512 use axum::Form;
2513 use axum::Json;
2514 use serde::Deserialize;
2515 use serde::Serialize;
2516 use serde_json::json;
2517
2518 #[tokio::test]
2519 async fn it_should_match_json_from_file() {
2520 let app = Router::new().route(
2521 &"/json",
2522 get(|| async {
2523 Json(json!(
2524 {
2525 "name": "Joe",
2526 "age": 20,
2527 }
2528 ))
2529 }),
2530 );
2531 let server = TestServer::new(app).unwrap();
2532
2533 server
2534 .get(&"/json")
2535 .await
2536 .assert_json_from_file("files/example.json");
2537 }
2538
2539 #[tokio::test]
2540 #[should_panic]
2541 async fn it_should_panic_when_not_match_the_file() {
2542 let app = Router::new().route(
2543 &"/json",
2544 get(|| async {
2545 Json(json!(
2546 {
2547 "name": "Julia",
2548 "age": 25,
2549 }
2550 ))
2551 }),
2552 );
2553 let server = TestServer::new(app).unwrap();
2554
2555 server
2556 .get(&"/json")
2557 .await
2558 .assert_json_from_file("files/example.json");
2559 }
2560
2561 #[tokio::test]
2562 #[should_panic]
2563 async fn it_should_panic_when_content_type_does_not_match() {
2564 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2565 struct ExampleResponse {
2566 name: String,
2567 age: u32,
2568 }
2569
2570 let app = Router::new().route(
2571 &"/form",
2572 get(|| async {
2573 Form(ExampleResponse {
2574 name: "Joe".to_string(),
2575 age: 20,
2576 })
2577 }),
2578 );
2579 let server = TestServer::new(app).unwrap();
2580
2581 server
2582 .get(&"/form")
2583 .await
2584 .assert_json_from_file("files/example.json");
2585 }
2586}
2587
2588#[cfg(feature = "yaml")]
2589#[cfg(test)]
2590mod test_assert_yaml {
2591 use crate::TestServer;
2592 use axum::routing::get;
2593 use axum::Form;
2594 use axum::Router;
2595 use axum_yaml::Yaml;
2596 use serde::Deserialize;
2597 use serde::Serialize;
2598
2599 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2600 struct ExampleResponse {
2601 name: String,
2602 age: u32,
2603 }
2604
2605 async fn route_get_form() -> Form<ExampleResponse> {
2606 Form(ExampleResponse {
2607 name: "Joe".to_string(),
2608 age: 20,
2609 })
2610 }
2611
2612 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2613 Yaml(ExampleResponse {
2614 name: "Joe".to_string(),
2615 age: 20,
2616 })
2617 }
2618
2619 #[tokio::test]
2620 async fn it_should_match_yaml_returned() {
2621 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2622
2623 let server = TestServer::new(app).unwrap();
2624
2625 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2626 name: "Joe".to_string(),
2627 age: 20,
2628 });
2629 }
2630
2631 #[tokio::test]
2632 #[should_panic]
2633 async fn it_should_panic_if_response_is_different() {
2634 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2635
2636 let server = TestServer::new(app).unwrap();
2637
2638 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2639 name: "Julia".to_string(),
2640 age: 25,
2641 });
2642 }
2643
2644 #[tokio::test]
2645 #[should_panic]
2646 async fn it_should_panic_if_response_is_form() {
2647 let app = Router::new().route(&"/form", get(route_get_form));
2648
2649 let server = TestServer::new(app).unwrap();
2650
2651 server.get(&"/form").await.assert_yaml(&ExampleResponse {
2652 name: "Joe".to_string(),
2653 age: 20,
2654 });
2655 }
2656}
2657
2658#[cfg(feature = "yaml")]
2659#[cfg(test)]
2660mod test_assert_yaml_from_file {
2661 use crate::TestServer;
2662 use axum::routing::get;
2663 use axum::routing::Router;
2664 use axum::Form;
2665 use axum_yaml::Yaml;
2666 use serde::Deserialize;
2667 use serde::Serialize;
2668 use serde_json::json;
2669
2670 #[tokio::test]
2671 async fn it_should_match_yaml_from_file() {
2672 let app = Router::new().route(
2673 &"/yaml",
2674 get(|| async {
2675 Yaml(json!(
2676 {
2677 "name": "Joe",
2678 "age": 20,
2679 }
2680 ))
2681 }),
2682 );
2683 let server = TestServer::new(app).unwrap();
2684
2685 server
2686 .get(&"/yaml")
2687 .await
2688 .assert_yaml_from_file("files/example.yaml");
2689 }
2690
2691 #[tokio::test]
2692 #[should_panic]
2693 async fn it_should_panic_when_not_match_the_file() {
2694 let app = Router::new().route(
2695 &"/yaml",
2696 get(|| async {
2697 Yaml(json!(
2698 {
2699 "name": "Julia",
2700 "age": 25,
2701 }
2702 ))
2703 }),
2704 );
2705 let server = TestServer::new(app).unwrap();
2706
2707 server
2708 .get(&"/yaml")
2709 .await
2710 .assert_yaml_from_file("files/example.yaml");
2711 }
2712
2713 #[tokio::test]
2714 #[should_panic]
2715 async fn it_should_panic_when_content_type_does_not_match() {
2716 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2717 struct ExampleResponse {
2718 name: String,
2719 age: u32,
2720 }
2721
2722 let app = Router::new().route(
2723 &"/form",
2724 get(|| async {
2725 Form(ExampleResponse {
2726 name: "Joe".to_string(),
2727 age: 20,
2728 })
2729 }),
2730 );
2731 let server = TestServer::new(app).unwrap();
2732
2733 server
2734 .get(&"/form")
2735 .await
2736 .assert_yaml_from_file("files/example.yaml");
2737 }
2738}
2739
2740#[cfg(test)]
2741mod test_assert_form {
2742 use crate::TestServer;
2743 use axum::routing::get;
2744 use axum::Form;
2745 use axum::Json;
2746 use axum::Router;
2747 use serde::Deserialize;
2748 use serde::Serialize;
2749
2750 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2751 struct ExampleResponse {
2752 name: String,
2753 age: u32,
2754 }
2755
2756 async fn route_get_form() -> Form<ExampleResponse> {
2757 Form(ExampleResponse {
2758 name: "Joe".to_string(),
2759 age: 20,
2760 })
2761 }
2762
2763 async fn route_get_json() -> Json<ExampleResponse> {
2764 Json(ExampleResponse {
2765 name: "Joe".to_string(),
2766 age: 20,
2767 })
2768 }
2769
2770 #[tokio::test]
2771 async fn it_should_match_form_returned() {
2772 let app = Router::new().route(&"/form", get(route_get_form));
2773
2774 let server = TestServer::new(app).unwrap();
2775
2776 server.get(&"/form").await.assert_form(&ExampleResponse {
2777 name: "Joe".to_string(),
2778 age: 20,
2779 });
2780 }
2781
2782 #[tokio::test]
2783 #[should_panic]
2784 async fn it_should_panic_if_response_is_different() {
2785 let app = Router::new().route(&"/form", get(route_get_form));
2786
2787 let server = TestServer::new(app).unwrap();
2788
2789 server.get(&"/form").await.assert_form(&ExampleResponse {
2790 name: "Julia".to_string(),
2791 age: 25,
2792 });
2793 }
2794
2795 #[tokio::test]
2796 #[should_panic]
2797 async fn it_should_panic_if_response_is_json() {
2798 let app = Router::new().route(&"/json", get(route_get_json));
2799
2800 let server = TestServer::new(app).unwrap();
2801
2802 server.get(&"/json").await.assert_form(&ExampleResponse {
2803 name: "Joe".to_string(),
2804 age: 20,
2805 });
2806 }
2807}
2808
2809#[cfg(test)]
2810mod test_text {
2811 use crate::TestServer;
2812 use axum::routing::get;
2813 use axum::Router;
2814
2815 #[tokio::test]
2816 async fn it_should_deserialize_into_text() {
2817 async fn route_get_text() -> String {
2818 "hello!".to_string()
2819 }
2820
2821 let app = Router::new().route(&"/text", get(route_get_text));
2822
2823 let server = TestServer::new(app).unwrap();
2824
2825 let response = server.get(&"/text").await.text();
2826
2827 assert_eq!(response, "hello!");
2828 }
2829}
2830
2831#[cfg(feature = "ws")]
2832#[cfg(test)]
2833mod test_into_websocket {
2834 use crate::TestServer;
2835
2836 use axum::extract::ws::WebSocket;
2837 use axum::extract::WebSocketUpgrade;
2838 use axum::response::Response;
2839 use axum::routing::get;
2840 use axum::Router;
2841
2842 fn new_test_router() -> Router {
2843 pub async fn route_get_websocket(ws: WebSocketUpgrade) -> Response {
2844 async fn handle_ping_pong(mut socket: WebSocket) {
2845 while let Some(_) = socket.recv().await {
2846 }
2848 }
2849
2850 ws.on_upgrade(move |socket| handle_ping_pong(socket))
2851 }
2852
2853 let app = Router::new().route(&"/ws", get(route_get_websocket));
2854
2855 app
2856 }
2857
2858 #[tokio::test]
2859 async fn it_should_upgrade_on_http_transport() {
2860 let router = new_test_router();
2861 let server = TestServer::builder()
2862 .http_transport()
2863 .build(router)
2864 .unwrap();
2865
2866 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2867
2868 assert!(true);
2869 }
2870
2871 #[tokio::test]
2872 #[should_panic]
2873 async fn it_should_fail_to_upgrade_on_mock_transport() {
2874 let router = new_test_router();
2875 let server = TestServer::builder()
2876 .mock_transport()
2877 .build(router)
2878 .unwrap();
2879
2880 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2881 }
2882}