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::fmt::Formatter;
24use std::fmt::Result as FmtResult;
25use std::fs::File;
26use std::fs::read_to_string;
27use std::io::BufReader;
28use std::ops::RangeBounds;
29use std::path::Path;
30use url::Url;
31
32#[cfg(feature = "pretty-assertions")]
33use pretty_assertions::{assert_eq, assert_ne};
34
35#[cfg(feature = "ws")]
36use crate::TestWebSocket;
37#[cfg(feature = "ws")]
38use crate::internals::TestResponseWebSocket;
39
40#[cfg(not(feature = "old-json-diff"))]
41use expect_json::expect;
42#[cfg(not(feature = "old-json-diff"))]
43use expect_json::expect_json_eq;
44use http::Version;
45
46#[derive(Debug, Clone)]
143pub struct TestResponse {
144 version: Version,
145 method: Method,
146
147 full_request_url: Url,
149 headers: HeaderMap<HeaderValue>,
150 status_code: StatusCode,
151 response_body: Bytes,
152
153 #[cfg(feature = "ws")]
154 websockets: TestResponseWebSocket,
155}
156
157impl TestResponse {
158 pub(crate) fn new(
159 version: Version,
160 method: Method,
161 full_request_url: Url,
162 parts: Parts,
163 response_body: Bytes,
164
165 #[cfg(feature = "ws")] websockets: TestResponseWebSocket,
166 ) -> Self {
167 Self {
168 version,
169 method,
170 full_request_url,
171 headers: parts.headers,
172 status_code: parts.status,
173 response_body,
174
175 #[cfg(feature = "ws")]
176 websockets,
177 }
178 }
179
180 #[must_use]
214 pub fn text(&self) -> String {
215 String::from_utf8_lossy(self.as_bytes()).to_string()
216 }
217
218 #[must_use]
260 #[track_caller]
261 pub fn json<T>(&self) -> T
262 where
263 T: DeserializeOwned,
264 {
265 serde_json::from_slice::<T>(self.as_bytes())
266 .with_context(|| {
267 let debug_request_format = self.debug_request_format();
268
269 format!("Deserializing response from Json, for request {debug_request_format}")
270 })
271 .unwrap()
272 }
273
274 #[cfg(feature = "yaml")]
315 #[must_use]
316 #[track_caller]
317 pub fn yaml<T>(&self) -> T
318 where
319 T: DeserializeOwned,
320 {
321 serde_yaml::from_slice::<T>(self.as_bytes())
322 .with_context(|| {
323 let debug_request_format = self.debug_request_format();
324
325 format!("Deserializing response from YAML, for request {debug_request_format}")
326 })
327 .unwrap()
328 }
329
330 #[cfg(feature = "msgpack")]
371 #[must_use]
372 #[track_caller]
373 pub fn msgpack<T>(&self) -> T
374 where
375 T: DeserializeOwned,
376 {
377 rmp_serde::from_slice::<T>(self.as_bytes())
378 .with_context(|| {
379 let debug_request_format = self.debug_request_format();
380
381 format!("Deserializing response from MsgPack, for request {debug_request_format}")
382 })
383 .unwrap()
384 }
385
386 #[must_use]
427 #[track_caller]
428 pub fn form<T>(&self) -> T
429 where
430 T: DeserializeOwned,
431 {
432 serde_urlencoded::from_bytes::<T>(self.as_bytes())
433 .with_context(|| {
434 let debug_request_format = self.debug_request_format();
435
436 format!("Deserializing response from Form, for request {debug_request_format}")
437 })
438 .unwrap()
439 }
440
441 #[must_use]
443 pub fn as_bytes(&self) -> &Bytes {
444 &self.response_body
445 }
446
447 #[must_use]
450 pub fn into_bytes(self) -> Bytes {
451 self.response_body
452 }
453
454 #[must_use]
456 pub fn status_code(&self) -> StatusCode {
457 self.status_code
458 }
459
460 #[must_use]
462 pub fn request_method(&self) -> Method {
463 self.method.clone()
464 }
465
466 #[must_use]
468 pub fn request_url(&self) -> Url {
469 self.full_request_url.clone()
470 }
471
472 #[must_use]
478 pub fn maybe_header<N>(&self, name: N) -> Option<HeaderValue>
479 where
480 N: TryInto<HeaderName>,
481 N::Error: Debug,
482 {
483 let header_name = name
484 .try_into()
485 .expect("Failed to build HeaderName from name given");
486 self.headers.get(header_name).map(|h| h.to_owned())
487 }
488
489 #[must_use]
491 pub fn headers(&self) -> &HeaderMap<HeaderValue> {
492 &self.headers
493 }
494
495 #[must_use]
496 #[track_caller]
497 pub fn maybe_content_type(&self) -> Option<String> {
498 self.headers.get(http::header::CONTENT_TYPE).map(|header| {
499 header
500 .to_str()
501 .with_context(|| {
502 format!("Failed to decode header CONTENT_TYPE, received '{header:?}'")
503 })
504 .unwrap()
505 .to_string()
506 })
507 }
508
509 #[must_use]
510 pub fn content_type(&self) -> String {
511 self.maybe_content_type()
512 .expect("CONTENT_TYPE not found in response header")
513 }
514
515 #[must_use]
521 #[track_caller]
522 pub fn header<N>(&self, name: N) -> HeaderValue
523 where
524 N: TryInto<HeaderName> + Display + Clone,
525 N::Error: Debug,
526 {
527 let debug_header = name.clone();
528 let header_name = name
529 .try_into()
530 .expect("Failed to build HeaderName from name given, '{debug_header}'");
531 self.headers
532 .get(header_name)
533 .map(|h| h.to_owned())
534 .with_context(|| {
535 let debug_request_format = self.debug_request_format();
536
537 format!("Cannot find header {debug_header}, for request {debug_request_format}",)
538 })
539 .unwrap()
540 }
541
542 pub fn iter_headers(&self) -> impl Iterator<Item = (&'_ HeaderName, &'_ HeaderValue)> {
544 self.headers.iter()
545 }
546
547 pub fn iter_headers_by_name<N>(&self, name: N) -> impl Iterator<Item = &'_ HeaderValue>
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.get_all(header_name).iter()
557 }
558
559 #[must_use]
560 pub fn contains_header<N>(&self, name: N) -> bool
561 where
562 N: TryInto<HeaderName>,
563 N::Error: Debug,
564 {
565 let header_name = name
566 .try_into()
567 .expect("Failed to build HeaderName from name given");
568 self.headers.contains_key(header_name)
569 }
570
571 #[track_caller]
575 pub fn assert_contains_header<N>(&self, name: N)
576 where
577 N: TryInto<HeaderName> + Display + Clone,
578 N::Error: Debug,
579 {
580 let debug_header_name = name.clone();
581 let debug_request_format = self.debug_request_format();
582 let has_header = self.contains_header(name);
583
584 assert!(
585 has_header,
586 "Expected header '{debug_header_name}' to be present in response, header was not found, for request {debug_request_format}"
587 );
588 }
589
590 #[track_caller]
591 pub fn assert_header<N, V>(&self, name: N, value: V)
592 where
593 N: TryInto<HeaderName> + Display + Clone,
594 N::Error: Debug,
595 V: TryInto<HeaderValue>,
596 V::Error: Debug,
597 {
598 let debug_header_name = name.clone();
599 let header_name = name
600 .try_into()
601 .expect("Failed to build HeaderName from name given");
602 let expected_header_value = value
603 .try_into()
604 .expect("Could not turn given value into HeaderValue");
605 let debug_request_format = self.debug_request_format();
606 let maybe_found_header_value = self.maybe_header(header_name);
607
608 match maybe_found_header_value {
609 None => {
610 panic!(
611 "Expected header '{debug_header_name}' to be present in response, header was not found, for request {debug_request_format}"
612 )
613 }
614 Some(found_header_value) => {
615 assert_eq!(expected_header_value, found_header_value,)
616 }
617 }
618 }
619
620 #[must_use]
626 pub fn maybe_cookie(&self, cookie_name: &str) -> Option<Cookie<'static>> {
627 for cookie in self.iter_cookies() {
628 if cookie.name() == cookie_name {
629 return Some(cookie.into_owned());
630 }
631 }
632
633 None
634 }
635
636 #[must_use]
642 #[track_caller]
643 pub fn cookie(&self, cookie_name: &str) -> Cookie<'static> {
644 self.maybe_cookie(cookie_name)
645 .with_context(|| {
646 let debug_request_format = self.debug_request_format();
647
648 format!("Cannot find cookie {cookie_name}, for request {debug_request_format}")
649 })
650 .unwrap()
651 }
652
653 #[must_use]
658 pub fn cookies(&self) -> CookieJar {
659 let mut cookies = CookieJar::new();
660
661 for cookie in self.iter_cookies() {
662 cookies.add(cookie.into_owned());
663 }
664
665 cookies
666 }
667
668 #[track_caller]
670 pub fn iter_cookies(&self) -> impl Iterator<Item = Cookie<'_>> {
671 self.iter_headers_by_name(SET_COOKIE).map(|header| {
672 let header_str = header
673 .to_str()
674 .with_context(|| {
675 let debug_request_format = self.debug_request_format();
676
677 format!(
678 "Reading header 'Set-Cookie' as string, for request {debug_request_format}",
679 )
680 })
681 .unwrap();
682
683 Cookie::parse(header_str)
684 .with_context(|| {
685 let debug_request_format = self.debug_request_format();
686
687 format!("Parsing 'Set-Cookie' header, for request {debug_request_format}",)
688 })
689 .unwrap()
690 })
691 }
692
693 #[cfg(feature = "ws")]
725 #[must_use]
726 pub async fn into_websocket(self) -> TestWebSocket {
727 use crate::transport_layer::TransportLayerType;
728
729 if self.websockets.transport_type != TransportLayerType::Http {
731 unimplemented!(
732 "WebSocket requires a HTTP based transport layer, see `TestServerConfig::transport`"
733 );
734 }
735
736 let debug_request_format = self.debug_request_format().to_string();
737
738 let on_upgrade = self.websockets.maybe_on_upgrade.with_context(|| {
739 format!("Expected WebSocket upgrade to be found, it is None, for request {debug_request_format}")
740 })
741 .unwrap();
742
743 let upgraded = on_upgrade
744 .await
745 .with_context(|| {
746 format!("Failed to upgrade connection for, for request {debug_request_format}")
747 })
748 .unwrap();
749
750 TestWebSocket::new(upgraded).await
751 }
752
753 #[track_caller]
756 pub fn assert_text<C>(&self, expected: C)
757 where
758 C: AsRef<str>,
759 {
760 let expected_contents = expected.as_ref();
761 assert_eq!(expected_contents, &self.text());
762 }
763
764 #[track_caller]
766 pub fn assert_text_contains<C>(&self, expected: C)
767 where
768 C: AsRef<str>,
769 {
770 let expected_contents = expected.as_ref();
771 let received = self.text();
772 let is_contained = received.contains(expected_contents);
773
774 assert!(
775 is_contained,
776 "Failed to find '{expected_contents}', received '{received}'"
777 );
778 }
779
780 #[track_caller]
782 pub fn assert_text_from_file<P>(&self, path: P)
783 where
784 P: AsRef<Path>,
785 {
786 let path_ref = path.as_ref();
787 let expected = read_to_string(path_ref)
788 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
789 .unwrap();
790
791 self.assert_text(expected);
792 }
793
794 #[track_caller]
843 pub fn assert_json<T>(&self, expected: &T)
844 where
845 T: Serialize + DeserializeOwned + PartialEq<T> + Debug,
846 {
847 let received = self.json::<T>();
848
849 #[cfg(feature = "old-json-diff")]
850 {
851 assert_eq!(*expected, received);
852 }
853
854 #[cfg(not(feature = "old-json-diff"))]
855 {
856 if *expected != received {
857 if let Err(error) = expect_json_eq(&received, &expected) {
858 panic!(
859 "
860{error}
861",
862 );
863 }
864 }
865 }
866 }
867
868 #[track_caller]
906 pub fn assert_json_contains<T>(&self, expected: &T)
907 where
908 T: Serialize,
909 {
910 let received = self.json::<Value>();
911
912 #[cfg(feature = "old-json-diff")]
913 {
914 assert_json_diff::assert_json_include!(actual: received, expected: expected);
915 }
916
917 #[cfg(not(feature = "old-json-diff"))]
918 {
919 let expected_value = serde_json::to_value(expected).unwrap();
920 let result = expect_json_eq(
921 &received,
922 &expect::object().propagated_contains(expected_value),
923 );
924 if let Err(error) = result {
925 panic!(
926 "
927{error}
928",
929 );
930 }
931 }
932 }
933
934 #[track_caller]
963 pub fn assert_json_from_file<P>(&self, path: P)
964 where
965 P: AsRef<Path>,
966 {
967 let path_ref = path.as_ref();
968 let file = File::open(path_ref)
969 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
970 .unwrap();
971
972 let reader = BufReader::new(file);
973 let expected = serde_json::from_reader::<_, serde_json::Value>(reader)
974 .with_context(|| {
975 format!(
976 "Failed to deserialize file '{}' as json",
977 path_ref.display()
978 )
979 })
980 .unwrap();
981
982 self.assert_json(&expected);
983 }
984
985 #[cfg(feature = "yaml")]
991 #[track_caller]
992 pub fn assert_yaml<T>(&self, other: &T)
993 where
994 T: DeserializeOwned + PartialEq<T> + Debug,
995 {
996 assert_eq!(*other, self.yaml::<T>());
997 }
998
999 #[cfg(feature = "yaml")]
1001 #[track_caller]
1002 pub fn assert_yaml_from_file<P>(&self, path: P)
1003 where
1004 P: AsRef<Path>,
1005 {
1006 let path_ref = path.as_ref();
1007 let file = File::open(path_ref)
1008 .with_context(|| format!("Failed to read from file '{}'", path_ref.display()))
1009 .unwrap();
1010
1011 let reader = BufReader::new(file);
1012 let expected = serde_yaml::from_reader::<_, serde_yaml::Value>(reader)
1013 .with_context(|| {
1014 format!(
1015 "Failed to deserialize file '{}' as yaml",
1016 path_ref.display()
1017 )
1018 })
1019 .unwrap();
1020
1021 self.assert_yaml(&expected);
1022 }
1023
1024 #[cfg(feature = "msgpack")]
1030 #[track_caller]
1031 pub fn assert_msgpack<T>(&self, other: &T)
1032 where
1033 T: DeserializeOwned + PartialEq<T> + Debug,
1034 {
1035 assert_eq!(*other, self.msgpack::<T>());
1036 }
1037
1038 #[track_caller]
1044 pub fn assert_form<T>(&self, other: &T)
1045 where
1046 T: DeserializeOwned + PartialEq<T> + Debug,
1047 {
1048 assert_eq!(*other, self.form::<T>());
1049 }
1050
1051 #[track_caller]
1053 pub fn assert_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_eq!(
1060 expected_status_code, self.status_code,
1061 "Expected status code to be {expected_debug}, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1062 );
1063 }
1064
1065 #[track_caller]
1067 pub fn assert_not_status(&self, expected_status_code: StatusCode) {
1068 let received_debug = StatusCodeFormatter(self.status_code);
1069 let expected_debug = StatusCodeFormatter(expected_status_code);
1070 let debug_request_format = self.debug_request_format();
1071 let debug_body = DebugResponseBody(self);
1072
1073 assert_ne!(
1074 expected_status_code, self.status_code,
1075 "Expected status code to not be {expected_debug}, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1076 );
1077 }
1078
1079 #[track_caller]
1082 pub fn assert_status_success(&self) {
1083 let status_code = self.status_code.as_u16();
1084 let received_debug = StatusCodeFormatter(self.status_code);
1085 let debug_request_format = self.debug_request_format();
1086 let debug_body = DebugResponseBody(self);
1087
1088 assert!(
1089 200 <= status_code && status_code <= 299,
1090 "Expect status code within 2xx range, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1091 );
1092 }
1093
1094 #[track_caller]
1097 pub fn assert_status_failure(&self) {
1098 let status_code = self.status_code.as_u16();
1099 let received_debug = StatusCodeFormatter(self.status_code);
1100 let debug_request_format = self.debug_request_format();
1101 let debug_body = DebugResponseBody(self);
1102
1103 assert!(
1104 status_code < 200 || 299 < status_code,
1105 "Expect status code outside 2xx range, received {received_debug}, for request {debug_request_format}, with body {debug_body}"
1106 );
1107 }
1108
1109 #[track_caller]
1147 pub fn assert_status_in_range<R, S>(&self, expected_status_range: R)
1148 where
1149 R: RangeBounds<S> + TryIntoRangeBounds<StatusCode> + Debug,
1150 S: TryInto<StatusCode>,
1151 {
1152 let range = TryIntoRangeBounds::<StatusCode>::try_into_range_bounds(expected_status_range)
1153 .expect("Failed to convert status code");
1154
1155 let status_code = self.status_code();
1156 let is_in_range = range.contains(&status_code);
1157 let debug_request_format = self.debug_request_format();
1158 let debug_body = DebugResponseBody(self);
1159
1160 assert!(
1161 is_in_range,
1162 "Expected status to be in range {}, received {status_code}, for request {debug_request_format}, with body {debug_body}",
1163 format_status_code_range(range)
1164 );
1165 }
1166
1167 #[track_caller]
1205 pub fn assert_status_not_in_range<R, S>(&self, expected_status_range: R)
1206 where
1207 R: RangeBounds<S> + TryIntoRangeBounds<StatusCode> + Debug,
1208 S: TryInto<StatusCode>,
1209 {
1210 let range = TryIntoRangeBounds::<StatusCode>::try_into_range_bounds(expected_status_range)
1211 .expect("Failed to convert status code");
1212
1213 let status_code = self.status_code();
1214 let is_not_in_range = !range.contains(&status_code);
1215 let debug_request_format = self.debug_request_format();
1216 let debug_body = DebugResponseBody(self);
1217
1218 assert!(
1219 is_not_in_range,
1220 "Expected status is not in range {}, received {status_code}, for request {debug_request_format}, with body {debug_body}",
1221 format_status_code_range(range)
1222 );
1223 }
1224
1225 #[track_caller]
1227 pub fn assert_status_ok(&self) {
1228 self.assert_status(StatusCode::OK)
1229 }
1230
1231 #[track_caller]
1233 pub fn assert_status_not_ok(&self) {
1234 self.assert_not_status(StatusCode::OK)
1235 }
1236
1237 #[track_caller]
1239 pub fn assert_status_no_content(&self) {
1240 self.assert_status(StatusCode::NO_CONTENT)
1241 }
1242
1243 #[track_caller]
1245 pub fn assert_status_see_other(&self) {
1246 self.assert_status(StatusCode::SEE_OTHER)
1247 }
1248
1249 #[track_caller]
1251 pub fn assert_status_bad_request(&self) {
1252 self.assert_status(StatusCode::BAD_REQUEST)
1253 }
1254
1255 #[track_caller]
1257 pub fn assert_status_not_found(&self) {
1258 self.assert_status(StatusCode::NOT_FOUND)
1259 }
1260
1261 #[track_caller]
1263 pub fn assert_status_unauthorized(&self) {
1264 self.assert_status(StatusCode::UNAUTHORIZED)
1265 }
1266
1267 #[track_caller]
1269 pub fn assert_status_forbidden(&self) {
1270 self.assert_status(StatusCode::FORBIDDEN)
1271 }
1272
1273 pub fn assert_status_conflict(&self) {
1275 self.assert_status(StatusCode::CONFLICT)
1276 }
1277
1278 #[track_caller]
1282 pub fn assert_status_payload_too_large(&self) {
1283 self.assert_status(StatusCode::PAYLOAD_TOO_LARGE)
1284 }
1285
1286 #[track_caller]
1288 pub fn assert_status_unprocessable_entity(&self) {
1289 self.assert_status(StatusCode::UNPROCESSABLE_ENTITY)
1290 }
1291
1292 #[track_caller]
1294 pub fn assert_status_too_many_requests(&self) {
1295 self.assert_status(StatusCode::TOO_MANY_REQUESTS)
1296 }
1297
1298 #[track_caller]
1303 pub fn assert_status_switching_protocols(&self) {
1304 self.assert_status(StatusCode::SWITCHING_PROTOCOLS)
1305 }
1306
1307 #[track_caller]
1309 pub fn assert_status_internal_server_error(&self) {
1310 self.assert_status(StatusCode::INTERNAL_SERVER_ERROR)
1311 }
1312
1313 #[track_caller]
1315 pub fn assert_status_service_unavailable(&self) {
1316 self.assert_status(StatusCode::SERVICE_UNAVAILABLE)
1317 }
1318
1319 fn debug_request_format(&self) -> RequestPathFormatter<'_> {
1320 RequestPathFormatter::new(&self.method, self.full_request_url.as_str(), None)
1321 }
1322}
1323
1324impl From<TestResponse> for Bytes {
1325 fn from(response: TestResponse) -> Self {
1326 response.into_bytes()
1327 }
1328}
1329
1330impl Display for TestResponse {
1334 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
1335 let version_str = version_str(self.version);
1336 let status = self.status_code();
1337 let status_int = status.as_u16();
1338 let status_reason = status.canonical_reason().unwrap_or("");
1339
1340 writeln!(f, "{version_str} {status_int} {status_reason}",)?;
1341
1342 for (name, value) in self.headers() {
1343 writeln!(f, "{}: {}", name, value.to_str().unwrap_or("<binary>"))?;
1344 }
1345
1346 writeln!(f)?;
1347
1348 let body_raw = String::from_utf8_lossy(&self.response_body);
1349 writeln!(f, "{body_raw}")?;
1350
1351 Ok(())
1352 }
1353}
1354
1355fn version_str(version: Version) -> &'static str {
1356 match version {
1357 Version::HTTP_09 => "HTTP/0.9",
1358 Version::HTTP_10 => "HTTP/1.0",
1359 Version::HTTP_11 => "HTTP/1.1",
1360 Version::HTTP_2 => "HTTP/2",
1361 Version::HTTP_3 => "HTTP/3",
1362 _ => "HTTP/?",
1363 }
1364}
1365
1366#[cfg(test)]
1367mod test_assert_header {
1368 use crate::TestServer;
1369 use axum::Router;
1370 use axum::http::HeaderMap;
1371 use axum::routing::get;
1372
1373 async fn route_get_header() -> HeaderMap {
1374 let mut headers = HeaderMap::new();
1375 headers.insert("x-my-custom-header", "content".parse().unwrap());
1376 headers
1377 }
1378
1379 #[tokio::test]
1380 async fn it_should_not_panic_if_contains_header_and_content_matches() {
1381 let router = Router::new().route(&"/header", get(route_get_header));
1382
1383 let server = TestServer::new(router).unwrap();
1384
1385 server
1386 .get(&"/header")
1387 .await
1388 .assert_header("x-my-custom-header", "content");
1389 }
1390
1391 #[tokio::test]
1392 #[should_panic]
1393 async fn it_should_panic_if_contains_header_and_content_does_not_match() {
1394 let router = Router::new().route(&"/header", get(route_get_header));
1395
1396 let server = TestServer::new(router).unwrap();
1397
1398 server
1399 .get(&"/header")
1400 .await
1401 .assert_header("x-my-custom-header", "different-content");
1402 }
1403
1404 #[tokio::test]
1405 #[should_panic]
1406 async fn it_should_panic_if_not_contains_header() {
1407 let router = Router::new().route(&"/header", get(route_get_header));
1408
1409 let server = TestServer::new(router).unwrap();
1410
1411 server
1412 .get(&"/header")
1413 .await
1414 .assert_header("x-custom-header-not-found", "content");
1415 }
1416}
1417
1418#[cfg(test)]
1419mod test_assert_contains_header {
1420 use crate::TestServer;
1421 use axum::Router;
1422 use axum::http::HeaderMap;
1423 use axum::routing::get;
1424
1425 async fn route_get_header() -> HeaderMap {
1426 let mut headers = HeaderMap::new();
1427 headers.insert("x-my-custom-header", "content".parse().unwrap());
1428 headers
1429 }
1430
1431 #[tokio::test]
1432 async fn it_should_not_panic_if_contains_header() {
1433 let router = Router::new().route(&"/header", get(route_get_header));
1434
1435 let server = TestServer::new(router).unwrap();
1436
1437 server
1438 .get(&"/header")
1439 .await
1440 .assert_contains_header("x-my-custom-header");
1441 }
1442
1443 #[tokio::test]
1444 #[should_panic]
1445 async fn it_should_panic_if_not_contains_header() {
1446 let router = Router::new().route(&"/header", get(route_get_header));
1447
1448 let server = TestServer::new(router).unwrap();
1449
1450 server
1451 .get(&"/header")
1452 .await
1453 .assert_contains_header("x-custom-header-not-found");
1454 }
1455}
1456
1457#[cfg(test)]
1458mod test_assert_success {
1459 use crate::TestServer;
1460 use axum::Router;
1461 use axum::routing::get;
1462 use http::StatusCode;
1463
1464 pub async fn route_get_pass() -> StatusCode {
1465 StatusCode::OK
1466 }
1467
1468 pub async fn route_get_fail() -> StatusCode {
1469 StatusCode::SERVICE_UNAVAILABLE
1470 }
1471
1472 #[tokio::test]
1473 async fn it_should_pass_when_200() {
1474 let router = Router::new()
1475 .route(&"/pass", get(route_get_pass))
1476 .route(&"/fail", get(route_get_fail));
1477
1478 let server = TestServer::new(router).unwrap();
1479
1480 let response = server.get(&"/pass").await;
1481
1482 response.assert_status_success()
1483 }
1484
1485 #[tokio::test]
1486 #[should_panic]
1487 async fn it_should_panic_when_not_200() {
1488 let router = Router::new()
1489 .route(&"/pass", get(route_get_pass))
1490 .route(&"/fail", get(route_get_fail));
1491
1492 let server = TestServer::new(router).unwrap();
1493
1494 let response = server.get(&"/fail").expect_failure().await;
1495
1496 response.assert_status_success()
1497 }
1498}
1499
1500#[cfg(test)]
1501mod test_assert_failure {
1502 use crate::TestServer;
1503 use axum::Router;
1504 use axum::routing::get;
1505 use http::StatusCode;
1506
1507 pub async fn route_get_pass() -> StatusCode {
1508 StatusCode::OK
1509 }
1510
1511 pub async fn route_get_fail() -> StatusCode {
1512 StatusCode::SERVICE_UNAVAILABLE
1513 }
1514
1515 #[tokio::test]
1516 async fn it_should_pass_when_not_200() {
1517 let router = Router::new()
1518 .route(&"/pass", get(route_get_pass))
1519 .route(&"/fail", get(route_get_fail));
1520
1521 let server = TestServer::new(router).unwrap();
1522 let response = server.get(&"/fail").expect_failure().await;
1523
1524 response.assert_status_failure()
1525 }
1526
1527 #[tokio::test]
1528 #[should_panic]
1529 async fn it_should_panic_when_200() {
1530 let router = Router::new()
1531 .route(&"/pass", get(route_get_pass))
1532 .route(&"/fail", get(route_get_fail));
1533
1534 let server = TestServer::new(router).unwrap();
1535 let response = server.get(&"/pass").await;
1536
1537 response.assert_status_failure()
1538 }
1539}
1540
1541#[cfg(test)]
1542mod test_assert_status {
1543 use crate::TestServer;
1544 use axum::Router;
1545 use axum::routing::get;
1546 use http::StatusCode;
1547
1548 pub async fn route_get_ok() -> StatusCode {
1549 StatusCode::OK
1550 }
1551
1552 #[tokio::test]
1553 async fn it_should_pass_if_given_right_status_code() {
1554 let router = Router::new().route(&"/ok", get(route_get_ok));
1555 let server = TestServer::new(router).unwrap();
1556
1557 server.get(&"/ok").await.assert_status(StatusCode::OK);
1558 }
1559
1560 #[tokio::test]
1561 #[should_panic]
1562 async fn it_should_panic_when_status_code_does_not_match() {
1563 let router = Router::new().route(&"/ok", get(route_get_ok));
1564 let server = TestServer::new(router).unwrap();
1565
1566 server.get(&"/ok").await.assert_status(StatusCode::ACCEPTED);
1567 }
1568}
1569
1570#[cfg(test)]
1571mod test_assert_not_status {
1572 use crate::TestServer;
1573 use axum::Router;
1574 use axum::routing::get;
1575 use http::StatusCode;
1576
1577 pub async fn route_get_ok() -> StatusCode {
1578 StatusCode::OK
1579 }
1580
1581 #[tokio::test]
1582 async fn it_should_pass_if_status_code_does_not_match() {
1583 let router = Router::new().route(&"/ok", get(route_get_ok));
1584 let server = TestServer::new(router).unwrap();
1585
1586 server
1587 .get(&"/ok")
1588 .await
1589 .assert_not_status(StatusCode::ACCEPTED);
1590 }
1591
1592 #[tokio::test]
1593 #[should_panic]
1594 async fn it_should_panic_if_status_code_matches() {
1595 let router = Router::new().route(&"/ok", get(route_get_ok));
1596 let server = TestServer::new(router).unwrap();
1597
1598 server.get(&"/ok").await.assert_not_status(StatusCode::OK);
1599 }
1600}
1601
1602#[cfg(test)]
1603mod test_assert_status_in_range {
1604 use crate::TestServer;
1605 use axum::routing::Router;
1606 use axum::routing::get;
1607 use http::StatusCode;
1608 use std::ops::RangeFull;
1609
1610 #[tokio::test]
1611 async fn it_should_be_true_when_within_int_range() {
1612 let app = Router::new().route(
1613 &"/status",
1614 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1615 );
1616
1617 TestServer::new(app)
1618 .unwrap()
1619 .get(&"/status")
1620 .await
1621 .assert_status_in_range(200..299);
1622 }
1623
1624 #[tokio::test]
1625 async fn it_should_be_true_when_within_status_code_range() {
1626 let app = Router::new().route(
1627 &"/status",
1628 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1629 );
1630
1631 TestServer::new(app)
1632 .unwrap()
1633 .get(&"/status")
1634 .await
1635 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1636 }
1637
1638 #[tokio::test]
1639 #[should_panic]
1640 async fn it_should_be_false_when_outside_int_range() {
1641 let app = Router::new().route(
1642 &"/status",
1643 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1644 );
1645
1646 TestServer::new(app)
1647 .unwrap()
1648 .get(&"/status")
1649 .await
1650 .assert_status_in_range(200..299);
1651 }
1652
1653 #[tokio::test]
1654 #[should_panic]
1655 async fn it_should_be_false_when_outside_status_code_range() {
1656 let app = Router::new().route(
1657 &"/status",
1658 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1659 );
1660
1661 TestServer::new(app)
1662 .unwrap()
1663 .get(&"/status")
1664 .await
1665 .assert_status_in_range(StatusCode::OK..StatusCode::IM_USED);
1666 }
1667
1668 #[tokio::test]
1669 async fn it_should_be_true_when_within_inclusive_range() {
1670 let app = Router::new().route(
1671 &"/status",
1672 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1673 );
1674
1675 TestServer::new(app)
1676 .unwrap()
1677 .get(&"/status")
1678 .await
1679 .assert_status_in_range(200..=299);
1680 }
1681
1682 #[tokio::test]
1683 #[should_panic]
1684 async fn it_should_be_false_when_outside_inclusive_range() {
1685 let app = Router::new().route(
1686 &"/status",
1687 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1688 );
1689
1690 TestServer::new(app)
1691 .unwrap()
1692 .get(&"/status")
1693 .await
1694 .assert_status_in_range(200..=299);
1695 }
1696
1697 #[tokio::test]
1698 async fn it_should_be_true_when_within_to_range() {
1699 let app = Router::new().route(
1700 &"/status",
1701 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1702 );
1703
1704 TestServer::new(app)
1705 .unwrap()
1706 .get(&"/status")
1707 .await
1708 .assert_status_in_range(..299);
1709 }
1710
1711 #[tokio::test]
1712 #[should_panic]
1713 async fn it_should_be_false_when_outside_to_range() {
1714 let app = Router::new().route(
1715 &"/status",
1716 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1717 );
1718
1719 TestServer::new(app)
1720 .unwrap()
1721 .get(&"/status")
1722 .await
1723 .assert_status_in_range(..299);
1724 }
1725
1726 #[tokio::test]
1727 async fn it_should_be_true_when_within_to_inclusive_range() {
1728 let app = Router::new().route(
1729 &"/status",
1730 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1731 );
1732
1733 TestServer::new(app)
1734 .unwrap()
1735 .get(&"/status")
1736 .await
1737 .assert_status_in_range(..=299);
1738 }
1739
1740 #[tokio::test]
1741 #[should_panic]
1742 async fn it_should_be_false_when_outside_to_inclusive_range() {
1743 let app = Router::new().route(
1744 &"/status",
1745 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1746 );
1747
1748 TestServer::new(app)
1749 .unwrap()
1750 .get(&"/status")
1751 .await
1752 .assert_status_in_range(..=299);
1753 }
1754
1755 #[tokio::test]
1756 async fn it_should_be_true_when_within_from_range() {
1757 let app = Router::new().route(
1758 &"/status",
1759 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1760 );
1761
1762 TestServer::new(app)
1763 .unwrap()
1764 .get(&"/status")
1765 .await
1766 .assert_status_in_range(200..);
1767 }
1768
1769 #[tokio::test]
1770 #[should_panic]
1771 async fn it_should_be_false_when_outside_from_range() {
1772 let app = Router::new().route(
1773 &"/status",
1774 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1775 );
1776
1777 TestServer::new(app)
1778 .unwrap()
1779 .get(&"/status")
1780 .await
1781 .assert_status_in_range(500..);
1782 }
1783
1784 #[tokio::test]
1785 async fn it_should_be_true_for_rull_range() {
1786 let app = Router::new().route(
1787 &"/status",
1788 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1789 );
1790
1791 TestServer::new(app)
1792 .unwrap()
1793 .get(&"/status")
1794 .await
1795 .assert_status_in_range::<RangeFull, StatusCode>(..);
1796 }
1797}
1798
1799#[cfg(test)]
1800mod test_assert_status_not_in_range {
1801 use crate::TestServer;
1802 use axum::routing::Router;
1803 use axum::routing::get;
1804 use http::StatusCode;
1805 use std::ops::RangeFull;
1806
1807 #[tokio::test]
1808 #[should_panic]
1809 async fn it_should_be_false_when_within_int_range() {
1810 let app = Router::new().route(
1811 &"/status",
1812 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1813 );
1814
1815 TestServer::new(app)
1816 .unwrap()
1817 .get(&"/status")
1818 .await
1819 .assert_status_not_in_range(200..299);
1820 }
1821
1822 #[tokio::test]
1823 #[should_panic]
1824 async fn it_should_be_false_when_within_status_code_range() {
1825 let app = Router::new().route(
1826 &"/status",
1827 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1828 );
1829
1830 TestServer::new(app)
1831 .unwrap()
1832 .get(&"/status")
1833 .await
1834 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1835 }
1836
1837 #[tokio::test]
1838 async fn it_should_be_true_when_outside_int_range() {
1839 let app = Router::new().route(
1840 &"/status",
1841 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1842 );
1843
1844 TestServer::new(app)
1845 .unwrap()
1846 .get(&"/status")
1847 .await
1848 .assert_status_not_in_range(200..299);
1849 }
1850
1851 #[tokio::test]
1852 async fn it_should_be_true_when_outside_status_code_range() {
1853 let app = Router::new().route(
1854 &"/status",
1855 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1856 );
1857
1858 TestServer::new(app)
1859 .unwrap()
1860 .get(&"/status")
1861 .await
1862 .assert_status_not_in_range(StatusCode::OK..StatusCode::IM_USED);
1863 }
1864
1865 #[tokio::test]
1866 #[should_panic]
1867 async fn it_should_be_false_when_within_inclusive_range() {
1868 let app = Router::new().route(
1869 &"/status",
1870 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1871 );
1872
1873 TestServer::new(app)
1874 .unwrap()
1875 .get(&"/status")
1876 .await
1877 .assert_status_not_in_range(200..=299);
1878 }
1879
1880 #[tokio::test]
1881 async fn it_should_be_true_when_outside_inclusive_range() {
1882 let app = Router::new().route(
1883 &"/status",
1884 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1885 );
1886
1887 TestServer::new(app)
1888 .unwrap()
1889 .get(&"/status")
1890 .await
1891 .assert_status_not_in_range(200..=299);
1892 }
1893
1894 #[tokio::test]
1895 #[should_panic]
1896 async fn it_should_be_false_when_within_to_range() {
1897 let app = Router::new().route(
1898 &"/status",
1899 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1900 );
1901
1902 TestServer::new(app)
1903 .unwrap()
1904 .get(&"/status")
1905 .await
1906 .assert_status_not_in_range(..299);
1907 }
1908
1909 #[tokio::test]
1910 async fn it_should_be_true_when_outside_to_range() {
1911 let app = Router::new().route(
1912 &"/status",
1913 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1914 );
1915
1916 TestServer::new(app)
1917 .unwrap()
1918 .get(&"/status")
1919 .await
1920 .assert_status_not_in_range(..299);
1921 }
1922
1923 #[tokio::test]
1924 #[should_panic]
1925 async fn it_should_be_false_when_within_to_inclusive_range() {
1926 let app = Router::new().route(
1927 &"/status",
1928 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1929 );
1930
1931 TestServer::new(app)
1932 .unwrap()
1933 .get(&"/status")
1934 .await
1935 .assert_status_not_in_range(..=299);
1936 }
1937
1938 #[tokio::test]
1939 async fn it_should_be_true_when_outside_to_inclusive_range() {
1940 let app = Router::new().route(
1941 &"/status",
1942 get(|| async { StatusCode::INTERNAL_SERVER_ERROR }),
1943 );
1944
1945 TestServer::new(app)
1946 .unwrap()
1947 .get(&"/status")
1948 .await
1949 .assert_status_not_in_range(..=299);
1950 }
1951
1952 #[tokio::test]
1953 #[should_panic]
1954 async fn it_should_be_false_when_within_from_range() {
1955 let app = Router::new().route(
1956 &"/status",
1957 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1958 );
1959
1960 TestServer::new(app)
1961 .unwrap()
1962 .get(&"/status")
1963 .await
1964 .assert_status_not_in_range(200..);
1965 }
1966
1967 #[tokio::test]
1968 async fn it_should_be_true_when_outside_from_range() {
1969 let app = Router::new().route(
1970 &"/status",
1971 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1972 );
1973
1974 TestServer::new(app)
1975 .unwrap()
1976 .get(&"/status")
1977 .await
1978 .assert_status_not_in_range(500..);
1979 }
1980
1981 #[tokio::test]
1982 #[should_panic]
1983 async fn it_should_be_false_for_rull_range() {
1984 let app = Router::new().route(
1985 &"/status",
1986 get(|| async { StatusCode::NON_AUTHORITATIVE_INFORMATION }),
1987 );
1988
1989 TestServer::new(app)
1990 .unwrap()
1991 .get(&"/status")
1992 .await
1993 .assert_status_not_in_range::<RangeFull, StatusCode>(..);
1994 }
1995}
1996
1997#[cfg(test)]
1998mod test_into_bytes {
1999 use crate::TestServer;
2000 use axum::Json;
2001 use axum::Router;
2002 use axum::routing::get;
2003 use serde_json::Value;
2004 use serde_json::json;
2005
2006 async fn route_get_json() -> Json<Value> {
2007 Json(json!({
2008 "message": "it works?"
2009 }))
2010 }
2011
2012 #[tokio::test]
2013 async fn it_should_deserialize_into_json() {
2014 let app = Router::new().route(&"/json", get(route_get_json));
2015
2016 let server = TestServer::new(app).unwrap();
2017
2018 let bytes = server.get(&"/json").await.into_bytes();
2019 let text = String::from_utf8_lossy(&bytes);
2020
2021 assert_eq!(text, r#"{"message":"it works?"}"#);
2022 }
2023}
2024
2025#[cfg(test)]
2026mod test_content_type {
2027 use crate::TestServer;
2028 use axum::Json;
2029 use axum::Router;
2030 use axum::routing::get;
2031 use serde::Deserialize;
2032 use serde::Serialize;
2033
2034 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2035 struct ExampleResponse {
2036 name: String,
2037 age: u32,
2038 }
2039
2040 #[tokio::test]
2041 async fn it_should_retrieve_json_content_type_for_json() {
2042 let app = Router::new().route(
2043 &"/json",
2044 get(|| async {
2045 Json(ExampleResponse {
2046 name: "Joe".to_string(),
2047 age: 20,
2048 })
2049 }),
2050 );
2051
2052 let server = TestServer::new(app).unwrap();
2053
2054 let content_type = server.get(&"/json").await.content_type();
2055 assert_eq!(content_type, "application/json");
2056 }
2057
2058 #[cfg(feature = "yaml")]
2059 #[tokio::test]
2060 async fn it_should_retrieve_yaml_content_type_for_yaml() {
2061 use axum_yaml::Yaml;
2062
2063 let app = Router::new().route(
2064 &"/yaml",
2065 get(|| async {
2066 Yaml(ExampleResponse {
2067 name: "Joe".to_string(),
2068 age: 20,
2069 })
2070 }),
2071 );
2072
2073 let server = TestServer::new(app).unwrap();
2074
2075 let content_type = server.get(&"/yaml").await.content_type();
2076 assert_eq!(content_type, "application/yaml");
2077 }
2078}
2079
2080#[cfg(test)]
2081mod test_json {
2082 use crate::TestServer;
2083 use axum::Json;
2084 use axum::Router;
2085 use axum::routing::get;
2086 use serde::Deserialize;
2087 use serde::Serialize;
2088
2089 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2090 struct ExampleResponse {
2091 name: String,
2092 age: u32,
2093 }
2094
2095 async fn route_get_json() -> Json<ExampleResponse> {
2096 Json(ExampleResponse {
2097 name: "Joe".to_string(),
2098 age: 20,
2099 })
2100 }
2101
2102 #[tokio::test]
2103 async fn it_should_deserialize_into_json() {
2104 let app = Router::new().route(&"/json", get(route_get_json));
2105
2106 let server = TestServer::new(app).unwrap();
2107
2108 let response = server.get(&"/json").await.json::<ExampleResponse>();
2109
2110 assert_eq!(
2111 response,
2112 ExampleResponse {
2113 name: "Joe".to_string(),
2114 age: 20,
2115 }
2116 );
2117 }
2118}
2119
2120#[cfg(feature = "yaml")]
2121#[cfg(test)]
2122mod test_yaml {
2123 use crate::TestServer;
2124 use axum::Router;
2125 use axum::routing::get;
2126 use axum_yaml::Yaml;
2127 use serde::Deserialize;
2128 use serde::Serialize;
2129
2130 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2131 struct ExampleResponse {
2132 name: String,
2133 age: u32,
2134 }
2135
2136 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2137 Yaml(ExampleResponse {
2138 name: "Joe".to_string(),
2139 age: 20,
2140 })
2141 }
2142
2143 #[tokio::test]
2144 async fn it_should_deserialize_into_yaml() {
2145 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2146
2147 let server = TestServer::new(app).unwrap();
2148
2149 let response = server.get(&"/yaml").await.yaml::<ExampleResponse>();
2150
2151 assert_eq!(
2152 response,
2153 ExampleResponse {
2154 name: "Joe".to_string(),
2155 age: 20,
2156 }
2157 );
2158 }
2159}
2160
2161#[cfg(feature = "msgpack")]
2162#[cfg(test)]
2163mod test_msgpack {
2164 use crate::TestServer;
2165 use axum::Router;
2166 use axum::routing::get;
2167 use axum_msgpack::MsgPack;
2168 use serde::Deserialize;
2169 use serde::Serialize;
2170
2171 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2172 struct ExampleResponse {
2173 name: String,
2174 age: u32,
2175 }
2176
2177 async fn route_get_msgpack() -> MsgPack<ExampleResponse> {
2178 MsgPack(ExampleResponse {
2179 name: "Joe".to_string(),
2180 age: 20,
2181 })
2182 }
2183
2184 #[tokio::test]
2185 async fn it_should_deserialize_into_msgpack() {
2186 let app = Router::new().route(&"/msgpack", get(route_get_msgpack));
2187
2188 let server = TestServer::new(app).unwrap();
2189
2190 let response = server.get(&"/msgpack").await.msgpack::<ExampleResponse>();
2191
2192 assert_eq!(
2193 response,
2194 ExampleResponse {
2195 name: "Joe".to_string(),
2196 age: 20,
2197 }
2198 );
2199 }
2200}
2201
2202#[cfg(test)]
2203mod test_form {
2204 use crate::TestServer;
2205 use axum::Form;
2206 use axum::Router;
2207 use axum::routing::get;
2208 use serde::Deserialize;
2209 use serde::Serialize;
2210
2211 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2212 struct ExampleResponse {
2213 name: String,
2214 age: u32,
2215 }
2216
2217 async fn route_get_form() -> Form<ExampleResponse> {
2218 Form(ExampleResponse {
2219 name: "Joe".to_string(),
2220 age: 20,
2221 })
2222 }
2223
2224 #[tokio::test]
2225 async fn it_should_deserialize_into_form() {
2226 let app = Router::new().route(&"/form", get(route_get_form));
2227
2228 let server = TestServer::new(app).unwrap();
2229
2230 let response = server.get(&"/form").await.form::<ExampleResponse>();
2231
2232 assert_eq!(
2233 response,
2234 ExampleResponse {
2235 name: "Joe".to_string(),
2236 age: 20,
2237 }
2238 );
2239 }
2240}
2241
2242#[cfg(test)]
2243mod test_from {
2244 use crate::TestServer;
2245 use axum::Router;
2246 use axum::routing::get;
2247 use bytes::Bytes;
2248
2249 #[tokio::test]
2250 async fn it_should_turn_into_response_bytes() {
2251 let app = Router::new().route(&"/text", get(|| async { "This is some example text" }));
2252 let server = TestServer::new(app).unwrap();
2253
2254 let response = server.get(&"/text").await;
2255 let bytes: Bytes = response.into();
2256 let text = String::from_utf8_lossy(&bytes);
2257 assert_eq!(text, "This is some example text");
2258 }
2259}
2260
2261#[cfg(test)]
2262mod test_assert_text {
2263 use crate::TestServer;
2264 use axum::Router;
2265 use axum::routing::get;
2266
2267 fn new_test_server() -> TestServer {
2268 async fn route_get_text() -> &'static str {
2269 "This is some example text"
2270 }
2271
2272 let app = Router::new().route(&"/text", get(route_get_text));
2273 TestServer::new(app).unwrap()
2274 }
2275
2276 #[tokio::test]
2277 async fn it_should_match_whole_text() {
2278 let server = new_test_server();
2279
2280 server
2281 .get(&"/text")
2282 .await
2283 .assert_text("This is some example text");
2284 }
2285
2286 #[tokio::test]
2287 #[should_panic]
2288 async fn it_should_not_match_partial_text() {
2289 let server = new_test_server();
2290
2291 server.get(&"/text").await.assert_text("some example");
2292 }
2293
2294 #[tokio::test]
2295 #[should_panic]
2296 async fn it_should_not_match_different_text() {
2297 let server = new_test_server();
2298
2299 server.get(&"/text").await.assert_text("🦊");
2300 }
2301}
2302
2303#[cfg(test)]
2304mod test_assert_text_contains {
2305 use crate::TestServer;
2306 use axum::Router;
2307 use axum::routing::get;
2308
2309 fn new_test_server() -> TestServer {
2310 async fn route_get_text() -> &'static str {
2311 "This is some example text"
2312 }
2313
2314 let app = Router::new().route(&"/text", get(route_get_text));
2315 TestServer::new(app).unwrap()
2316 }
2317
2318 #[tokio::test]
2319 async fn it_should_match_whole_text() {
2320 let server = new_test_server();
2321
2322 server
2323 .get(&"/text")
2324 .await
2325 .assert_text_contains("This is some example text");
2326 }
2327
2328 #[tokio::test]
2329 async fn it_should_match_partial_text() {
2330 let server = new_test_server();
2331
2332 server
2333 .get(&"/text")
2334 .await
2335 .assert_text_contains("some example");
2336 }
2337
2338 #[tokio::test]
2339 #[should_panic]
2340 async fn it_should_not_match_different_text() {
2341 let server = new_test_server();
2342
2343 server.get(&"/text").await.assert_text_contains("🦊");
2344 }
2345}
2346
2347#[cfg(test)]
2348mod test_assert_text_from_file {
2349 use crate::TestServer;
2350 use axum::routing::Router;
2351 use axum::routing::get;
2352
2353 #[tokio::test]
2354 async fn it_should_match_from_file() {
2355 let app = Router::new().route(&"/text", get(|| async { "hello!" }));
2356 let server = TestServer::new(app).unwrap();
2357
2358 server
2359 .get(&"/text")
2360 .await
2361 .assert_text_from_file("files/example.txt");
2362 }
2363
2364 #[tokio::test]
2365 #[should_panic]
2366 async fn it_should_panic_when_not_match_the_file() {
2367 let app = Router::new().route(&"/text", get(|| async { "🦊" }));
2368 let server = TestServer::new(app).unwrap();
2369
2370 server
2371 .get(&"/text")
2372 .await
2373 .assert_text_from_file("files/example.txt");
2374 }
2375}
2376
2377#[cfg(test)]
2378mod test_assert_json {
2379 use super::*;
2380 use crate::TestServer;
2381 use axum::Form;
2382 use axum::Json;
2383 use axum::Router;
2384 use axum::routing::get;
2385 use serde::Deserialize;
2386 use serde_json::json;
2387
2388 #[cfg(not(feature = "old-json-diff"))]
2389 use crate::testing::ExpectStrMinLen;
2390
2391 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2392 struct ExampleResponse {
2393 name: String,
2394 age: u32,
2395 }
2396
2397 async fn route_get_form() -> Form<ExampleResponse> {
2398 Form(ExampleResponse {
2399 name: "Joe".to_string(),
2400 age: 20,
2401 })
2402 }
2403
2404 async fn route_get_json() -> Json<ExampleResponse> {
2405 Json(ExampleResponse {
2406 name: "Joe".to_string(),
2407 age: 20,
2408 })
2409 }
2410
2411 #[tokio::test]
2412 async fn it_should_match_json_returned() {
2413 let app = Router::new().route(&"/json", get(route_get_json));
2414
2415 let server = TestServer::new(app).unwrap();
2416
2417 server.get(&"/json").await.assert_json(&ExampleResponse {
2418 name: "Joe".to_string(),
2419 age: 20,
2420 });
2421 }
2422
2423 #[tokio::test]
2424 async fn it_should_match_json_returned_using_json_value() {
2425 let app = Router::new().route(&"/json", get(route_get_json));
2426
2427 let server = TestServer::new(app).unwrap();
2428
2429 server.get(&"/json").await.assert_json(&json!({
2430 "name": "Joe",
2431 "age": 20,
2432 }));
2433 }
2434
2435 #[tokio::test]
2436 #[should_panic]
2437 async fn it_should_panic_if_response_is_different() {
2438 let app = Router::new().route(&"/json", get(route_get_json));
2439
2440 let server = TestServer::new(app).unwrap();
2441
2442 server.get(&"/json").await.assert_json(&ExampleResponse {
2443 name: "Julia".to_string(),
2444 age: 25,
2445 });
2446 }
2447
2448 #[tokio::test]
2449 #[should_panic]
2450 async fn it_should_panic_if_response_is_form() {
2451 let app = Router::new().route(&"/form", get(route_get_form));
2452
2453 let server = TestServer::new(app).unwrap();
2454
2455 server.get(&"/form").await.assert_json(&ExampleResponse {
2456 name: "Joe".to_string(),
2457 age: 20,
2458 });
2459 }
2460
2461 #[cfg(not(feature = "old-json-diff"))]
2462 #[tokio::test]
2463 async fn it_should_work_with_custom_expect_op() {
2464 let app = Router::new().route(&"/json", get(route_get_json));
2465 let server = TestServer::new(app).unwrap();
2466
2467 server.get(&"/json").await.assert_json(&json!({
2468 "name": ExpectStrMinLen { min: 3 },
2469 "age": 20,
2470 }));
2471 }
2472
2473 #[cfg(not(feature = "old-json-diff"))]
2474 #[tokio::test]
2475 #[should_panic]
2476 async fn it_should_panic_if_custom_expect_op_fails() {
2477 let app = Router::new().route(&"/json", get(route_get_json));
2478 let server = TestServer::new(app).unwrap();
2479
2480 server.get(&"/json").await.assert_json(&json!({
2481 "name": ExpectStrMinLen { min: 10 },
2482 "age": 20,
2483 }));
2484 }
2485}
2486
2487#[cfg(test)]
2488mod test_assert_json_contains {
2489 use crate::TestServer;
2490 use axum::Form;
2491 use axum::Json;
2492 use axum::Router;
2493 use axum::routing::get;
2494 use serde::Deserialize;
2495 use serde::Serialize;
2496 use serde_json::json;
2497 use std::time::Instant;
2498
2499 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2500 struct ExampleResponse {
2501 time: u64,
2502 name: String,
2503 age: u32,
2504 }
2505
2506 async fn route_get_form() -> Form<ExampleResponse> {
2507 Form(ExampleResponse {
2508 time: Instant::now().elapsed().as_millis() as u64,
2509 name: "Joe".to_string(),
2510 age: 20,
2511 })
2512 }
2513
2514 async fn route_get_json() -> Json<ExampleResponse> {
2515 Json(ExampleResponse {
2516 time: Instant::now().elapsed().as_millis() as u64,
2517 name: "Joe".to_string(),
2518 age: 20,
2519 })
2520 }
2521
2522 #[tokio::test]
2523 async fn it_should_match_subset_of_json_returned() {
2524 let app = Router::new().route(&"/json", get(route_get_json));
2525 let server = TestServer::new(app).unwrap();
2526
2527 server.get(&"/json").await.assert_json_contains(&json!({
2528 "name": "Joe",
2529 "age": 20,
2530 }));
2531 }
2532
2533 #[tokio::test]
2534 #[should_panic]
2535 async fn it_should_panic_if_response_is_different() {
2536 let app = Router::new().route(&"/json", get(route_get_json));
2537 let server = TestServer::new(app).unwrap();
2538
2539 server
2540 .get(&"/json")
2541 .await
2542 .assert_json_contains(&ExampleResponse {
2543 time: 1234,
2544 name: "Julia".to_string(),
2545 age: 25,
2546 });
2547 }
2548
2549 #[tokio::test]
2550 #[should_panic]
2551 async fn it_should_panic_if_response_is_form() {
2552 let app = Router::new().route(&"/form", get(route_get_form));
2553 let server = TestServer::new(app).unwrap();
2554
2555 server.get(&"/form").await.assert_json_contains(&json!({
2556 "name": "Joe",
2557 "age": 20,
2558 }));
2559 }
2560
2561 #[tokio::test]
2563 async fn it_should_propagate_contains_to_sub_objects() {
2564 let json_result = json!({ "a": {"prop1": "value1"} }).to_string();
2565 let app = Router::new().route(&"/json", get(|| async { json_result }));
2566
2567 let server = TestServer::new(app).unwrap();
2568 let response = server.get("/json").await;
2569
2570 response.assert_json_contains(&json!({ "a": {} }));
2571 }
2572}
2573
2574#[cfg(test)]
2575mod test_assert_json_from_file {
2576 use crate::TestServer;
2577 use axum::Form;
2578 use axum::Json;
2579 use axum::routing::Router;
2580 use axum::routing::get;
2581 use serde::Deserialize;
2582 use serde::Serialize;
2583 use serde_json::json;
2584
2585 #[tokio::test]
2586 async fn it_should_match_json_from_file() {
2587 let app = Router::new().route(
2588 &"/json",
2589 get(|| async {
2590 Json(json!(
2591 {
2592 "name": "Joe",
2593 "age": 20,
2594 }
2595 ))
2596 }),
2597 );
2598 let server = TestServer::new(app).unwrap();
2599
2600 server
2601 .get(&"/json")
2602 .await
2603 .assert_json_from_file("files/example.json");
2604 }
2605
2606 #[tokio::test]
2607 #[should_panic]
2608 async fn it_should_panic_when_not_match_the_file() {
2609 let app = Router::new().route(
2610 &"/json",
2611 get(|| async {
2612 Json(json!(
2613 {
2614 "name": "Julia",
2615 "age": 25,
2616 }
2617 ))
2618 }),
2619 );
2620 let server = TestServer::new(app).unwrap();
2621
2622 server
2623 .get(&"/json")
2624 .await
2625 .assert_json_from_file("files/example.json");
2626 }
2627
2628 #[tokio::test]
2629 #[should_panic]
2630 async fn it_should_panic_when_content_type_does_not_match() {
2631 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2632 struct ExampleResponse {
2633 name: String,
2634 age: u32,
2635 }
2636
2637 let app = Router::new().route(
2638 &"/form",
2639 get(|| async {
2640 Form(ExampleResponse {
2641 name: "Joe".to_string(),
2642 age: 20,
2643 })
2644 }),
2645 );
2646 let server = TestServer::new(app).unwrap();
2647
2648 server
2649 .get(&"/form")
2650 .await
2651 .assert_json_from_file("files/example.json");
2652 }
2653}
2654
2655#[cfg(feature = "yaml")]
2656#[cfg(test)]
2657mod test_assert_yaml {
2658 use crate::TestServer;
2659 use axum::Form;
2660 use axum::Router;
2661 use axum::routing::get;
2662 use axum_yaml::Yaml;
2663 use serde::Deserialize;
2664 use serde::Serialize;
2665
2666 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2667 struct ExampleResponse {
2668 name: String,
2669 age: u32,
2670 }
2671
2672 async fn route_get_form() -> Form<ExampleResponse> {
2673 Form(ExampleResponse {
2674 name: "Joe".to_string(),
2675 age: 20,
2676 })
2677 }
2678
2679 async fn route_get_yaml() -> Yaml<ExampleResponse> {
2680 Yaml(ExampleResponse {
2681 name: "Joe".to_string(),
2682 age: 20,
2683 })
2684 }
2685
2686 #[tokio::test]
2687 async fn it_should_match_yaml_returned() {
2688 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2689
2690 let server = TestServer::new(app).unwrap();
2691
2692 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2693 name: "Joe".to_string(),
2694 age: 20,
2695 });
2696 }
2697
2698 #[tokio::test]
2699 #[should_panic]
2700 async fn it_should_panic_if_response_is_different() {
2701 let app = Router::new().route(&"/yaml", get(route_get_yaml));
2702
2703 let server = TestServer::new(app).unwrap();
2704
2705 server.get(&"/yaml").await.assert_yaml(&ExampleResponse {
2706 name: "Julia".to_string(),
2707 age: 25,
2708 });
2709 }
2710
2711 #[tokio::test]
2712 #[should_panic]
2713 async fn it_should_panic_if_response_is_form() {
2714 let app = Router::new().route(&"/form", get(route_get_form));
2715
2716 let server = TestServer::new(app).unwrap();
2717
2718 server.get(&"/form").await.assert_yaml(&ExampleResponse {
2719 name: "Joe".to_string(),
2720 age: 20,
2721 });
2722 }
2723}
2724
2725#[cfg(feature = "yaml")]
2726#[cfg(test)]
2727mod test_assert_yaml_from_file {
2728 use crate::TestServer;
2729 use axum::Form;
2730 use axum::routing::Router;
2731 use axum::routing::get;
2732 use axum_yaml::Yaml;
2733 use serde::Deserialize;
2734 use serde::Serialize;
2735 use serde_json::json;
2736
2737 #[tokio::test]
2738 async fn it_should_match_yaml_from_file() {
2739 let app = Router::new().route(
2740 &"/yaml",
2741 get(|| async {
2742 Yaml(json!(
2743 {
2744 "name": "Joe",
2745 "age": 20,
2746 }
2747 ))
2748 }),
2749 );
2750 let server = TestServer::new(app).unwrap();
2751
2752 server
2753 .get(&"/yaml")
2754 .await
2755 .assert_yaml_from_file("files/example.yaml");
2756 }
2757
2758 #[tokio::test]
2759 #[should_panic]
2760 async fn it_should_panic_when_not_match_the_file() {
2761 let app = Router::new().route(
2762 &"/yaml",
2763 get(|| async {
2764 Yaml(json!(
2765 {
2766 "name": "Julia",
2767 "age": 25,
2768 }
2769 ))
2770 }),
2771 );
2772 let server = TestServer::new(app).unwrap();
2773
2774 server
2775 .get(&"/yaml")
2776 .await
2777 .assert_yaml_from_file("files/example.yaml");
2778 }
2779
2780 #[tokio::test]
2781 #[should_panic]
2782 async fn it_should_panic_when_content_type_does_not_match() {
2783 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2784 struct ExampleResponse {
2785 name: String,
2786 age: u32,
2787 }
2788
2789 let app = Router::new().route(
2790 &"/form",
2791 get(|| async {
2792 Form(ExampleResponse {
2793 name: "Joe".to_string(),
2794 age: 20,
2795 })
2796 }),
2797 );
2798 let server = TestServer::new(app).unwrap();
2799
2800 server
2801 .get(&"/form")
2802 .await
2803 .assert_yaml_from_file("files/example.yaml");
2804 }
2805}
2806
2807#[cfg(test)]
2808mod test_assert_form {
2809 use crate::TestServer;
2810 use axum::Form;
2811 use axum::Json;
2812 use axum::Router;
2813 use axum::routing::get;
2814 use serde::Deserialize;
2815 use serde::Serialize;
2816
2817 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2818 struct ExampleResponse {
2819 name: String,
2820 age: u32,
2821 }
2822
2823 async fn route_get_form() -> Form<ExampleResponse> {
2824 Form(ExampleResponse {
2825 name: "Joe".to_string(),
2826 age: 20,
2827 })
2828 }
2829
2830 async fn route_get_json() -> Json<ExampleResponse> {
2831 Json(ExampleResponse {
2832 name: "Joe".to_string(),
2833 age: 20,
2834 })
2835 }
2836
2837 #[tokio::test]
2838 async fn it_should_match_form_returned() {
2839 let app = Router::new().route(&"/form", get(route_get_form));
2840
2841 let server = TestServer::new(app).unwrap();
2842
2843 server.get(&"/form").await.assert_form(&ExampleResponse {
2844 name: "Joe".to_string(),
2845 age: 20,
2846 });
2847 }
2848
2849 #[tokio::test]
2850 #[should_panic]
2851 async fn it_should_panic_if_response_is_different() {
2852 let app = Router::new().route(&"/form", get(route_get_form));
2853
2854 let server = TestServer::new(app).unwrap();
2855
2856 server.get(&"/form").await.assert_form(&ExampleResponse {
2857 name: "Julia".to_string(),
2858 age: 25,
2859 });
2860 }
2861
2862 #[tokio::test]
2863 #[should_panic]
2864 async fn it_should_panic_if_response_is_json() {
2865 let app = Router::new().route(&"/json", get(route_get_json));
2866
2867 let server = TestServer::new(app).unwrap();
2868
2869 server.get(&"/json").await.assert_form(&ExampleResponse {
2870 name: "Joe".to_string(),
2871 age: 20,
2872 });
2873 }
2874}
2875
2876#[cfg(test)]
2877mod test_text {
2878 use crate::TestServer;
2879 use axum::Router;
2880 use axum::routing::get;
2881
2882 #[tokio::test]
2883 async fn it_should_deserialize_into_text() {
2884 async fn route_get_text() -> String {
2885 "hello!".to_string()
2886 }
2887
2888 let app = Router::new().route(&"/text", get(route_get_text));
2889
2890 let server = TestServer::new(app).unwrap();
2891
2892 let response = server.get(&"/text").await.text();
2893
2894 assert_eq!(response, "hello!");
2895 }
2896}
2897
2898#[cfg(feature = "ws")]
2899#[cfg(test)]
2900mod test_into_websocket {
2901 use crate::TestServer;
2902
2903 use axum::Router;
2904 use axum::extract::WebSocketUpgrade;
2905 use axum::extract::ws::WebSocket;
2906 use axum::response::Response;
2907 use axum::routing::get;
2908
2909 fn new_test_router() -> Router {
2910 pub async fn route_get_websocket(ws: WebSocketUpgrade) -> Response {
2911 async fn handle_ping_pong(mut socket: WebSocket) {
2912 while let Some(_) = socket.recv().await {
2913 }
2915 }
2916
2917 ws.on_upgrade(move |socket| handle_ping_pong(socket))
2918 }
2919
2920 let app = Router::new().route(&"/ws", get(route_get_websocket));
2921
2922 app
2923 }
2924
2925 #[tokio::test]
2926 async fn it_should_upgrade_on_http_transport() {
2927 let router = new_test_router();
2928 let server = TestServer::builder()
2929 .http_transport()
2930 .build(router)
2931 .unwrap();
2932
2933 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2934
2935 assert!(true);
2936 }
2937
2938 #[tokio::test]
2939 #[should_panic]
2940 async fn it_should_fail_to_upgrade_on_mock_transport() {
2941 let router = new_test_router();
2942 let server = TestServer::builder()
2943 .mock_transport()
2944 .build(router)
2945 .unwrap();
2946
2947 let _ = server.get_websocket(&"/ws").await.into_websocket().await;
2948 }
2949}
2950
2951#[cfg(test)]
2952mod test_fmt {
2953 use crate::TestServer;
2954 use axum::Json;
2955 use axum::Router;
2956 use axum::routing::get;
2957 use serde::Deserialize;
2958 use serde::Serialize;
2959
2960 #[derive(Serialize, Deserialize, PartialEq, Debug)]
2961 struct ExampleResponse {
2962 name: String,
2963 age: u32,
2964 }
2965
2966 async fn route_get_json() -> Json<ExampleResponse> {
2967 Json(ExampleResponse {
2968 name: "Joe".to_string(),
2969 age: 20,
2970 })
2971 }
2972
2973 #[tokio::test]
2974 async fn it_should_output_json_in_json_format() {
2975 let app = Router::new().route(&"/json", get(route_get_json));
2976 let server = TestServer::new(app).unwrap();
2977
2978 let response = server.get(&"/json").await;
2979 let output = format!("{response}");
2980
2981 assert_eq!(
2982 output,
2983 r#"HTTP/1.1 200 OK
2984content-type: application/json
2985content-length: 23
2986
2987{"name":"Joe","age":20}
2988"#
2989 );
2990 }
2991}