Repository: juhaku/utoipa
Pull request #1254 (2024-12-23 05:43:11)

utoipa: Replace `assert-json-diff` with snapshot testing via `insta`
- same as #1253, but for the `utoipa` crate this time


Patch:
diff --git a/utoipa/CHANGELOG.md b/utoipa/CHANGELOG.md
index 026d259..f189854 100644
--- a/utoipa/CHANGELOG.md
+++ b/utoipa/CHANGELOG.md
@@ -3,6 +3,12 @@
 **`utoipa`** is in direct correlation with **`utoipa-gen`** ([CHANGELOG.md](../utoipa-gen/CHANGELOG.md)). You might want
 to look into changes introduced to **`utoipa-gen`**.
 
+## Unreleased
+
+### Changed
+
+* Replace `assert-json-diff` with snapshot testing via `insta` (https://github.com/juhaku/utoipa/pull/1254)
+
 ## 5.3.0 - Dec 19 2024
 
 ### Fixed
diff --git a/utoipa/Cargo.toml b/utoipa/Cargo.toml
index 6e0d73a..0c5e758 100644
--- a/utoipa/Cargo.toml
+++ b/utoipa/Cargo.toml
@@ -56,7 +56,7 @@ utoipa-gen = { version = "5.3.0", path = "../utoipa-gen", optional = true }
 indexmap = { version = "2", features = ["serde"] }
 
 [dev-dependencies]
-assert-json-diff = "2"
+insta = { version = "1.41", features = ["json", "redactions"] }
 utoipa = { path = ".", features = ["debug"] }
 
 [package.metadata.docs.rs]
diff --git a/utoipa/src/lib.rs b/utoipa/src/lib.rs
index 251c7d1..f2e6185 100644
--- a/utoipa/src/lib.rs
+++ b/utoipa/src/lib.rs
@@ -848,7 +848,7 @@ mod utoipa {
 ///             .build()
 ///         )
 ///     );
-/// # assert_json_diff::assert_json_eq!(serde_json::to_value(&number).unwrap(), serde_json::to_value(&number2).unwrap());
+/// # assert_eq!(serde_json::to_value(&number).unwrap(), serde_json::to_value(&number2).unwrap());
 /// ```
 ///
 /// _**Construct a Pet object schema manually.**_
@@ -1564,7 +1564,7 @@ pub mod __dev {
 
 #[cfg(test)]
 mod tests {
-    use assert_json_diff::assert_json_eq;
+    use insta::assert_compact_json_snapshot;
     use serde_json::json;
 
     use super::*;
@@ -1600,117 +1600,31 @@ mod tests {
     #[cfg(not(feature = "non_strict_integers"))]
     #[test]
     fn test_partial_schema_strict_integers() {
-        use assert_json_diff::{assert_json_matches, CompareMode, Config, NumericMode};
-
-        for (name, schema, value) in [
-            (
-                "i8",
-                i8::schema(),
-                json!({"type": "integer", "format": "int32"}),
-            ),
-            (
-                "i16",
-                i16::schema(),
-                json!({"type": "integer", "format": "int32"}),
-            ),
-            (
-                "i32",
-                i32::schema(),
-                json!({"type": "integer", "format": "int32"}),
-            ),
-            (
-                "i64",
-                i64::schema(),
-                json!({"type": "integer", "format": "int64"}),
-            ),
-            ("i128", i128::schema(), json!({"type": "integer"})),
-            ("isize", isize::schema(), json!({"type": "integer"})),
-            (
-                "u8",
-                u8::schema(),
-                json!({"type": "integer", "format": "int32", "minimum": 0.0}),
-            ),
-            (
-                "u16",
-                u16::schema(),
-                json!({"type": "integer", "format": "int32", "minimum": 0.0}),
-            ),
-            (
-                "u32",
-                u32::schema(),
-                json!({"type": "integer", "format": "int32", "minimum": 0.0}),
-            ),
-            (
-                "u64",
-                u64::schema(),
-                json!({"type": "integer", "format": "int64", "minimum": 0.0}),
-            ),
-        ] {
-            println!(
-                "{name}: {json}",
-                json = serde_json::to_string(&schema).unwrap()
-            );
-            let schema = serde_json::to_value(schema).unwrap();
-
-            let config = Config::new(CompareMode::Strict).numeric_mode(NumericMode::AssumeFloat);
-            assert_json_matches!(schema, value, config);
-        }
+        assert_compact_json_snapshot!(i8::schema(), @r#"{"type": "integer", "format": "int32"}"#);
+        assert_compact_json_snapshot!(i16::schema(), @r#"{"type": "integer", "format": "int32"}"#);
+        assert_compact_json_snapshot!(i32::schema(), @r#"{"type": "integer", "format": "int32"}"#);
+        assert_compact_json_snapshot!(i64::schema(), @r#"{"type": "integer", "format": "int64"}"#);
+        assert_compact_json_snapshot!(i128::schema(), @r#"{"type": "integer"}"#);
+        assert_compact_json_snapshot!(isize::schema(), @r#"{"type": "integer"}"#);
+        assert_compact_json_snapshot!(u8::schema(), @r#"{"type": "integer", "format": "int32", "minimum": 0}"#);
+        assert_compact_json_snapshot!(u16::schema(), @r#"{"type": "integer", "format": "int32", "minimum": 0}"#);
+        assert_compact_json_snapshot!(u32::schema(), @r#"{"type": "integer", "format": "int32", "minimum": 0}"#);
+        assert_compact_json_snapshot!(u64::schema(), @r#"{"type": "integer", "format": "int64", "minimum": 0}"#);
     }
 
     #[cfg(feature = "non_strict_integers")]
     #[test]
     fn test_partial_schema_non_strict_integers() {
-        for (name, schema, value) in [
-            (
-                "i8",
-                i8::schema(),
-                json!({"type": "integer", "format": "int8"}),
-            ),
-            (
-                "i16",
-                i16::schema(),
-                json!({"type": "integer", "format": "int16"}),
-            ),
-            (
-                "i32",
-                i32::schema(),
-                json!({"type": "integer", "format": "int32"}),
-            ),
-            (
-                "i64",
-                i64::schema(),
-                json!({"type": "integer", "format": "int64"}),
-            ),
-            ("i128", i128::schema(), json!({"type": "integer"})),
-            ("isize", isize::schema(), json!({"type": "integer"})),
-            (
-                "u8",
-                u8::schema(),
-                json!({"type": "integer", "format": "uint8", "minimum": 0}),
-            ),
-            (
-                "u16",
-                u16::schema(),
-                json!({"type": "integer", "format": "uint16", "minimum": 0}),
-            ),
-            (
-                "u32",
-                u32::schema(),
-                json!({"type": "integer", "format": "uint32", "minimum": 0}),
-            ),
-            (
-                "u64",
-                u64::schema(),
-                json!({"type": "integer", "format": "uint64", "minimum": 0}),
-            ),
-        ] {
-            println!(
-                "{name}: {json}",
-                json = serde_json::to_string(&schema).unwrap()
-            );
-            let schema = serde_json::to_value(schema).unwrap();
-            assert_json_eq!(schema, value);
-        }
+        assert_compact_json_snapshot!(i8::schema(), @r#"{"type": "integer", "format": "int8"}"#);
+        assert_compact_json_snapshot!(i16::schema(), @r#"{"type": "integer", "format": "int16"}"#);
+        assert_compact_json_snapshot!(i32::schema(), @r#"{"type": "integer", "format": "int32"}"#);
+        assert_compact_json_snapshot!(i64::schema(), @r#"{"type": "integer", "format": "int64"}"#);
+        assert_compact_json_snapshot!(i128::schema(), @r#"{"type": "integer"}"#);
+        assert_compact_json_snapshot!(isize::schema(), @r#"{"type": "integer"}"#);
+        assert_compact_json_snapshot!(u8::schema(), @r#"{"type": "integer", "format": "uint8", "minimum": 0}"#);
+        assert_compact_json_snapshot!(u16::schema(), @r#"{"type": "integer", "format": "uint16", "minimum": 0}"#);
+        assert_compact_json_snapshot!(u32::schema(), @r#"{"type": "integer", "format": "int32", "minimum": 0}"#);
+        assert_compact_json_snapshot!(u64::schema(), @r#"{"type": "integer", "format": "int64", "minimum": 0}"#);
     }
 
     #[test]
@@ -1736,7 +1650,7 @@ mod tests {
                 json = serde_json::to_string(&schema).unwrap()
             );
             let schema = serde_json::to_value(schema).unwrap();
-            assert_json_eq!(schema, value);
+            assert_eq!(schema, value);
         }
     }
 }
diff --git a/utoipa/src/openapi.rs b/utoipa/src/openapi.rs
index e2fdc19..1925fdf 100644
--- a/utoipa/src/openapi.rs
+++ b/utoipa/src/openapi.rs
@@ -656,13 +656,11 @@ pub(crate) use builder;
 
 #[cfg(test)]
 mod tests {
-    use assert_json_diff::assert_json_eq;
-    use serde_json::json;
-
     use crate::openapi::{
         info::InfoBuilder,
         path::{OperationBuilder, PathsBuilder},
     };
+    use insta::assert_json_snapshot;
 
     use super::{response::Response, *};
 
@@ -673,8 +671,7 @@ mod tests {
     }
 
     #[test]
-    fn serialize_openapi_json_minimal_success() -> Result<(), serde_json::Error> {
-        let raw_json = include_str!("openapi/testdata/expected_openapi_minimal.json");
+    fn serialize_openapi_json_minimal_success() {
         let openapi = OpenApi::new(
             InfoBuilder::new()
                 .title("My api")
@@ -689,17 +686,12 @@ mod tests {
                 .build(),
             Paths::new(),
         );
-        let serialized = serde_json::to_string_pretty(&openapi)?;
 
-        assert_eq!(
-            serialized, raw_json,
-            "expected serialized json to match raw: \nserialized: \n{serialized} \nraw: \n{raw_json}"
-        );
-        Ok(())
+        assert_json_snapshot!(openapi);
     }
 
     #[test]
-    fn serialize_openapi_json_with_paths_success() -> Result<(), serde_json::Error> {
+    fn serialize_openapi_json_with_paths_success() {
         let openapi = OpenApi::new(
             Info::new("My big api", "1.1.0"),
             PathsBuilder::new()
@@ -726,14 +718,7 @@ mod tests {
                 ),
         );
 
-        let serialized = serde_json::to_string_pretty(&openapi)?;
-        let expected = include_str!("./openapi/testdata/expected_openapi_with_paths.json");
-
-        assert_eq!(
-            serialized, expected,
-            "expected serialized json to match raw: \nserialized: \n{serialized} \nraw: \n{expected}"
-        );
-        Ok(())
+        assert_json_snapshot!(openapi);
     }
 
     #[test]
@@ -795,61 +780,10 @@ mod tests {
             .build();
 
         api_1.merge(api_2);
-        let value = serde_json::to_value(&api_1).unwrap();
-
-        assert_eq!(
-            value,
-            json!(
-                {
-                  "openapi": "3.1.0",
-                  "info": {
-                    "title": "Api",
-                    "version": "v1"
-                  },
-                  "paths": {
-                    "/ap/v2/user": {
-                      "get": {
-                        "responses": {
-                          "200": {
-                            "description": "Get user success 2"
-                          }
-                        }
-                      }
-                    },
-                    "/api/v1/user": {
-                      "get": {
-                        "responses": {
-                          "200": {
-                            "description": "Get user success"
-                          }
-                        }
-                      }
-                    },
-                    "/api/v2/user": {
-                      "post": {
-                        "responses": {
-                          "200": {
-                            "description": "Get user success"
-                          }
-                        }
-                      }
-                    }
-                  },
-                  "components": {
-                    "schemas": {
-                      "User2": {
-                        "type": "object",
-                        "properties": {
-                          "name": {
-                            "type": "string"
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-            )
-        )
+
+        assert_json_snapshot!(api_1, {
+            ".paths" => insta::sorted_redaction()
+        });
     }
 
     #[test]
@@ -922,68 +856,10 @@ mod tests {
             .build();
 
         api_1.merge(api_2);
-        let value = serde_json::to_value(&api_1).unwrap();
-
-        assert_eq!(
-            value,
-            json!(
-                {
-                  "openapi": "3.1.0",
-                  "info": {
-                    "title": "Api",
-                    "version": "v1"
-                  },
-                  "paths": {
-                    "/api/v2/user": {
-                      "get": {
-                        "responses": {
-                          "200": {
-                            "description": "Get user success 2"
-                          }
-                        }
-                      },
-                      "post": {
-                        "responses": {
-                          "200": {
-                            "description": "Post user success 2"
-                          }
-                        }
-                      }
-                    },
-                    "/api/v1/user": {
-                      "get": {
-                        "responses": {
-                          "200": {
-                            "description": "Get user success 1"
-                          }
-                        }
-                      },
-                      "post": {
-                        "responses": {
-                          "200": {
-                            "description": "Post user success 1"
-                          }
-                        }
-                      }
-                    },
-                    "x-random": "Value",
-                    "x-v1-api": true,
-                  },
-                  "components": {
-                    "schemas": {
-                      "User2": {
-                        "type": "object",
-                        "properties": {
-                          "name": {
-                            "type": "string"
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-            )
-        )
+
+        assert_json_snapshot!(api_1, {
+            ".paths" => insta::sorted_redaction()
+        });
     }
 
     #[test]
@@ -1027,28 +903,7 @@ mod tests {
             .pointer("/paths")
             .expect("paths should exits in openapi");
 
-        assert_json_eq!(
-            paths,
-            json!({
-                "/api/v1/status": {
-                        "get": {
-                        "description": "Get status",
-                        "responses": {}
-                    }
-                },
-                "/api/v1/user/": {
-                    "get": {
-                        "description": "Get user details",
-                        "responses": {}
-                    }
-                },
-                "/api/v1/user/foo": {
-                    "post": {
-                        "responses": {}
-                    }
-                }
-            })
-        )
+        assert_json_snapshot!(paths);
     }
 
     #[test]
@@ -1060,19 +915,6 @@ mod tests {
             String::from("anything that serializes to Json").into(),
         );
 
-        let api_json = serde_json::to_value(api).expect("OpenApi must serialize to JSON");
-
-        assert_json_eq!(
-            api_json,
-            json!({
-                "info": {
-                    "title": "",
-                    "version": ""
-                },
-                "openapi": "3.1.0",
-                "paths": {},
-                "x-tagGroup": "anything that serializes to Json",
-            })
-        )
+        assert_json_snapshot!(api);
     }
 }
diff --git a/utoipa/src/openapi/request_body.rs b/utoipa/src/openapi/request_body.rs
index 17b34d5..6f21de6 100644
--- a/utoipa/src/openapi/request_body.rs
+++ b/utoipa/src/openapi/request_body.rs
@@ -126,10 +126,8 @@ impl RequestBodyExt for RequestBodyBuilder {
 
 #[cfg(test)]
 mod tests {
-    use assert_json_diff::assert_json_eq;
-    use serde_json::json;
-
     use super::{Content, RequestBody, RequestBodyBuilder, Required};
+    use insta::assert_json_snapshot;
 
     #[test]
     fn request_body_new() {
@@ -141,7 +139,7 @@ mod tests {
     }
 
     #[test]
-    fn request_body_builder() -> Result<(), serde_json::Error> {
+    fn request_body_builder() {
         let request_body = RequestBodyBuilder::new()
             .description(Some("A sample requestBody"))
             .required(Some(Required::True))
@@ -150,33 +148,15 @@ mod tests {
                 Content::new(Some(crate::openapi::Ref::from_schema_name("EmailPayload"))),
             )
             .build();
-        let serialized = serde_json::to_string_pretty(&request_body)?;
-        println!("serialized json:\n {serialized}");
-        assert_json_eq!(
-            request_body,
-            json!({
-              "description": "A sample requestBody",
-              "content": {
-                "application/json": {
-                  "schema": {
-                    "$ref": "#/components/schemas/EmailPayload"
-                  }
-                }
-              },
-              "required": true
-            })
-        );
-        Ok(())
+        assert_json_snapshot!(request_body);
     }
 }
 
 #[cfg(all(test, feature = "openapi_extensions"))]
 #[cfg_attr(doc_cfg, doc(cfg(feature = "openapi_extensions")))]
 mod openapi_extensions_tests {
-    use assert_json_diff::assert_json_eq;
-    use serde_json::json;
-
     use crate::openapi::request_body::RequestBodyBuilder;
+    use insta::assert_json_snapshot;
 
     use super::RequestBodyExt;
 
@@ -186,18 +166,7 @@ mod openapi_extensions_tests {
             .build()
             // build a RequestBody first to test the method
             .json_schema_ref("EmailPayload");
-        assert_json_eq!(
-            request_body,
-            json!({
-              "content": {
-                "application/json": {
-                  "schema": {
-                    "$ref": "#/components/schemas/EmailPayload"
-                  }
-                }
-              }
-            })
-        );
+        assert_json_snapshot!(request_body);
     }
 
     #[test]
@@ -205,17 +174,6 @@ mod openapi_extensions_tests {
         let request_body = RequestBodyBuilder::new()
             .json_schema_ref("EmailPayload")
             .build();
-        assert_json_eq!(
-            request_body,
-            json!({
-              "content": {
-                "application/json": {
-                  "schema": {
-                    "$ref": "#/components/schemas/EmailPayload"
-                  }
-                }
-              }
-            })
-        );
+        assert_json_snapshot!(request_body);
     }
 }
diff --git a/utoipa/src/openapi/response.rs b/utoipa/src/openapi/response.rs
index 5863523..62239b3 100644
--- a/utoipa/src/openapi/response.rs
+++ b/utoipa/src/openapi/response.rs
@@ -263,8 +263,7 @@ impl ResponseExt for ResponseBuilder {
 #[cfg(test)]
 mod tests {
     use super::{Content, ResponseBuilder, Responses};
-    use assert_json_diff::assert_json_eq;
-    use serde_json::json;
+    use insta::assert_json_snapshot;
 
     #[test]
     fn responses_new() {
@@ -274,7 +273,7 @@ mod tests {
     }
 
     #[test]
-    fn response_builder() -> Result<(), serde_json::Error> {
+    fn response_builder() {
         let request_body = ResponseBuilder::new()
             .description("A sample response")
             .content(
@@ -284,31 +283,14 @@ mod tests {
                 ))),
             )
             .build();
-        let serialized = serde_json::to_string_pretty(&request_body)?;
-        println!("serialized json:\n {serialized}");
-        assert_json_eq!(
-            request_body,
-            json!({
-              "description": "A sample response",
-              "content": {
-                "application/json": {
-                  "schema": {
-                    "$ref": "#/components/schemas/MySchemaPayload"
-                  }
-                }
-              }
-            })
-        );
-        Ok(())
+        assert_json_snapshot!(request_body);
     }
 }
 
 #[cfg(all(test, feature = "openapi_extensions"))]
 mod openapi_extensions_tests {
-    use assert_json_diff::assert_json_eq;
-    use serde_json::json;
-
     use crate::openapi::ResponseBuilder;
+    use insta::assert_json_snapshot;
 
     use super::ResponseExt;
 
@@ -319,19 +301,7 @@ mod openapi_extensions_tests {
             .build()
             .json_schema_ref("MySchemaPayload");
 
-        assert_json_eq!(
-            request_body,
-            json!({
-              "description": "A sample response",
-              "content": {
-                "application/json": {
-                  "schema": {
-                    "$ref": "#/components/schemas/MySchemaPayload"
-                  }
-                }
-              }
-            })
-        );
+        assert_json_snapshot!(request_body);
     }
 
     #[test]
@@ -340,18 +310,6 @@ mod openapi_extensions_tests {
             .description("A sample response")
             .json_schema_ref("MySchemaPayload")
             .build();
-        assert_json_eq!(
-            request_body,
-            json!({
-              "description": "A sample response",
-              "content": {
-                "application/json": {
-                  "schema": {
-                    "$ref": "#/components/schemas/MySchemaPayload"
-                  }
-                }
-              }
-            })
-        );
+        assert_json_snapshot!(request_body);
     }
 }
diff --git a/utoipa/src/openapi/schema.rs b/utoipa/src/openapi/schema.rs
index 823a869..859fb46 100644
--- a/utoipa/src/openapi/schema.rs
+++ b/utoipa/src/openapi/schema.rs
@@ -2125,7 +2125,7 @@ pub enum KnownFormat {
 
 #[cfg(test)]
 mod tests {
-    use assert_json_diff::assert_json_eq;
+    use insta::assert_json_snapshot;
     use serde_json::{json, Value};
 
     use super::*;
@@ -2297,72 +2297,72 @@ mod tests {
         let json_value = ObjectBuilder::new()
             .additional_properties(Some(ObjectBuilder::new().schema_type(Type::String)))
             .build();
-        assert_json_eq!(
-            json_value,
-            json!({
-                "type": "object",
-                "additionalProperties": {
-                    "type": "string"
-                }
-            })
-        );
+        assert_json_snapshot!(json_value, @r#"
+        {
+          "type": "object",
+          "additionalProperties": {
+            "type": "string"
+          }
+        }
+        "#);
 
         let json_value = ObjectBuilder::new()
             .additional_properties(Some(ArrayBuilder::new().items(ArrayItems::RefOrSchema(
                 Box::new(ObjectBuilder::new().schema_type(Type::Number).into()),
             ))))
             .build();
-        assert_json_eq!(
-            json_value,
-            json!({
-                "type": "object",
-                "additionalProperties": {
-                    "items": {
-                        "type": "number",
-                    },
-                    "type": "array",
-                }
-            })
-        );
+        assert_json_snapshot!(json_value, @r#"
+        {
+          "type": "object",
+          "additionalProperties": {
+            "type": "array",
+            "items": {
+              "type": "number"
+            }
+          }
+        }
+        "#);
 
         let json_value = ObjectBuilder::new()
             .additional_properties(Some(Ref::from_schema_name("ComplexModel")))
             .build();
-        assert_json_eq!(
-            json_value,
-            json!({
-                "type": "object",
-                "additionalProperties": {
-                    "$ref": "#/components/schemas/ComplexModel"
-                }
-            })
-        )
+        assert_json_snapshot!(json_value, @r##"
+        {
+          "type": "object",
+          "additionalProperties": {
+            "$ref": "#/components/schemas/ComplexModel"
+          }
+        }
+        "##);
     }
 
     #[test]
     fn test_object_with_title() {
         let json_value = ObjectBuilder::new().title(Some("SomeName")).build();
-        assert_json_eq!(
-            json_value,
-            json!({
-                "type": "object",
-                "title": "SomeName"
-            })
-        );
+        assert_json_snapshot!(json_value, @r#"
+        {
+          "type": "object",
+          "title": "SomeName"
+        }
+        "#);
     }
 
     #[test]
     fn derive_object_with_examples() {
-        let expected = r#"{"type":"object","examples":[{"age":20,"name":"bob the cat"}]}"#;
         let json_value = ObjectBuilder::new()
             .examples([Some(json!({"age": 20, "name": "bob the cat"}))])
             .build();
-
-        let value_string = serde_json::to_string(&json_value).unwrap();
-        assert_eq!(
-            value_string, expected,
-            "value string != expected string, {value_string} != {expected}"
-        );
+        assert_json_snapshot!(json_value, @r#"
+        {
+          "type": "object",
+          "examples": [
+            {
+              "age": 20,
+              "name": "bob the cat"
+            }
+          ]
+        }
+        "#);
     }
 
     fn get_json_path<'a>(value: &'a Value, path: &str) -> &'a Value {
@@ -2771,24 +2771,21 @@ mod tests {
             .item(Ref::from_schema_name("MyInt"))
             .discriminator(Some(discriminator))
             .build();
-        let json_value = serde_json::to_value(one_of).unwrap();
-
-        assert_json_eq!(
-            json_value,
-            json!({
-                "oneOf": [
-                    {
-                        "$ref": "#/components/schemas/MyInt"
-                    }
-                ],
-                "discriminator": {
-                    "propertyName": "type",
-                    "mapping": {
-                        "int": "#/components/schemas/MyInt"
-                    }
-                }
-            })
-        );
+        assert_json_snapshot!(one_of, @r##"
+        {
+          "oneOf": [
+            {
+              "$ref": "#/components/schemas/MyInt"
+            }
+          ],
+          "discriminator": {
+            "propertyName": "type",
+            "mapping": {
+              "int": "#/components/schemas/MyInt"
+            }
+          }
+        }
+        "##);
     }
 
     #[test]


Test patch:
diff --git a/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__openapi_extensions_tests__request_body_builder_ext.snap b/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__openapi_extensions_tests__request_body_builder_ext.snap
new file mode 100644
index 0000000..062cc52
--- /dev/null
+++ b/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__openapi_extensions_tests__request_body_builder_ext.snap
@@ -0,0 +1,14 @@
+---
+source: utoipa/src/openapi/request_body.rs
+expression: request_body
+snapshot_kind: text
+---
+{
+  "content": {
+    "application/json": {
+      "schema": {
+        "$ref": "#/components/schemas/EmailPayload"
+      }
+    }
+  }
+}
diff --git a/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__openapi_extensions_tests__request_body_ext.snap b/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__openapi_extensions_tests__request_body_ext.snap
new file mode 100644
index 0000000..062cc52
--- /dev/null
+++ b/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__openapi_extensions_tests__request_body_ext.snap
@@ -0,0 +1,14 @@
+---
+source: utoipa/src/openapi/request_body.rs
+expression: request_body
+snapshot_kind: text
+---
+{
+  "content": {
+    "application/json": {
+      "schema": {
+        "$ref": "#/components/schemas/EmailPayload"
+      }
+    }
+  }
+}
diff --git a/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__tests__request_body_builder.snap b/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__tests__request_body_builder.snap
new file mode 100644
index 0000000..83b990c
--- /dev/null
+++ b/utoipa/src/openapi/snapshots/utoipa__openapi__request_body__tests__request_body_builder.snap
@@ -0,0 +1,16 @@
+---
+source: utoipa/src/openapi/request_body.rs
+expression: request_body
+snapshot_kind: text
+---
+{
+  "description": "A sample requestBody",
+  "content": {
+    "application/json": {
+      "schema": {
+        "$ref": "#/components/schemas/EmailPayload"
+      }
+    }
+  },
+  "required": true
+}
diff --git a/utoipa/src/openapi/snapshots/utoipa__openapi__response__openapi_extensions_tests__response_builder_ext.snap b/utoipa/src/openapi/snapshots/utoipa__openapi__response__openapi_extensions_tests__response_builder_ext.snap
new file mode 100644
index 0000000..89c8196
--- /dev/null
+++ b/utoipa/src/openapi/snapshots/utoipa__openapi__response__openapi_extensions_tests__response_builder_ext.snap
@@ -0,0 +1,15 @@
+---
+source: utoipa/src/openapi/response.rs
+expression: request_body
+snapshot_kind: text
+---
+{
+  "description": "A sample response",
+  "content": {
+    "application/json": {
+      "schema": {
+        "$ref": "#/components/schemas/MySchemaPayload"
+      }
+    }
+  }
+}
diff --git a/utoipa/src/openapi/snapshots/utoipa__openapi__response__openapi_extensions_tests__response_ext.snap b/utoipa/src/openapi/snapshots/utoipa__openapi__response__openapi_extensions_tests__response_ext.snap
new file mode 100644
index 0000000..89c8196
--- /dev/null
+++ b/utoipa/src/openapi/snapshots/utoipa__openapi__response__openapi_extensions_tests__response_ext.snap
@@ -0,0 +1,15 @@
+---
+source: utoipa/src/openapi/response.rs
+expression: request_body
+snapshot_kind: text
+---
+{
+  "description": "A sample response",
+  "content": {
+    "application/json": {
+      "schema": {
+        "$ref": "#/components/schemas/MySchemaPayload"
+      }
+    }
+  }
+}
diff --git a/utoipa/src/openapi/snapshots/utoipa__openapi__response__tests__response_builder.snap b/utoipa/src/openapi/snapshots/utoipa__openapi__response__tests__response_builder.snap
new file mode 100644
index 0000000..89c8196
--- /dev/null
+++ b/utoipa/src/openapi/snapshots/utoipa__openapi__response__tests__response_builder.snap
@@ -0,0 +1,15 @@
+---
+source: utoipa/src/openapi/response.rs
+expression: request_body
+snapshot_kind: text
+---
+{
+  "description": "A sample response",
+  "content": {
+    "application/json": {
+      "schema": {
+        "$ref": "#/components/schemas/MySchemaPayload"
+      }
+    }
+  }
+}
diff --git a/utoipa/src/snapshots/utoipa__openapi__tests__merge_2_openapi_documents.snap b/utoipa/src/snapshots/utoipa__openapi__tests__merge_2_openapi_documents.snap
new file mode 100644
index 0000000..7d4a765
--- /dev/null
+++ b/utoipa/src/snapshots/utoipa__openapi__tests__merge_2_openapi_documents.snap
@@ -0,0 +1,53 @@
+---
+source: utoipa/src/openapi.rs
+expression: api_1
+snapshot_kind: text
+---
+{
+  "openapi": "3.1.0",
+  "info": {
+    "title": "Api",
+    "version": "v1"
+  },
+  "paths": {
+    "/ap/v2/user": {
+      "get": {
+        "responses": {
+          "200": {
+            "description": "Get user success 2"
+          }
+        }
+      }
+    },
+    "/api/v1/user": {
+      "get": {
+        "responses": {
+          "200": {
+            "description": "Get user success"
+          }
+        }
+      }
+    },
+    "/api/v2/user": {
+      "post": {
+        "responses": {
+          "200": {
+            "description": "Get user success"
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "User2": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/utoipa/src/snapshots/utoipa__openapi__tests__merge_same_path_diff_methods.snap b/utoipa/src/snapshots/utoipa__openapi__tests__merge_same_path_diff_methods.snap
new file mode 100644
index 0000000..2b04c92
--- /dev/null
+++ b/utoipa/src/snapshots/utoipa__openapi__tests__merge_same_path_diff_methods.snap
@@ -0,0 +1,60 @@
+---
+source: utoipa/src/openapi.rs
+expression: api_1
+snapshot_kind: text
+---
+{
+  "openapi": "3.1.0",
+  "info": {
+    "title": "Api",
+    "version": "v1"
+  },
+  "paths": {
+    "/api/v1/user": {
+      "get": {
+        "responses": {
+          "200": {
+            "description": "Get user success 1"
+          }
+        }
+      },
+      "post": {
+        "responses": {
+          "200": {
+            "description": "Post user success 1"
+          }
+        }
+      }
+    },
+    "/api/v2/user": {
+      "get": {
+        "responses": {
+          "200": {
+            "description": "Get user success 2"
+          }
+        }
+      },
+      "post": {
+        "responses": {
+          "200": {
+            "description": "Post user success 2"
+          }
+        }
+      }
+    },
+    "x-random": "Value",
+    "x-v1-api": true
+  },
+  "components": {
+    "schemas": {
+      "User2": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/utoipa/src/snapshots/utoipa__openapi__tests__nest_open_apis.snap b/utoipa/src/snapshots/utoipa__openapi__tests__nest_open_apis.snap
new file mode 100644
index 0000000..9123a8b
--- /dev/null
+++ b/utoipa/src/snapshots/utoipa__openapi__tests__nest_open_apis.snap
@@ -0,0 +1,24 @@
+---
+source: utoipa/src/openapi.rs
+expression: paths
+snapshot_kind: text
+---
+{
+  "/api/v1/status": {
+    "get": {
+      "description": "Get status",
+      "responses": {}
+    }
+  },
+  "/api/v1/user/": {
+    "get": {
+      "description": "Get user details",
+      "responses": {}
+    }
+  },
+  "/api/v1/user/foo": {
+    "post": {
+      "responses": {}
+    }
+  }
+}
diff --git a/utoipa/src/snapshots/utoipa__openapi__tests__openapi_custom_extension.snap b/utoipa/src/snapshots/utoipa__openapi__tests__openapi_custom_extension.snap
new file mode 100644
index 0000000..abb471f
--- /dev/null
+++ b/utoipa/src/snapshots/utoipa__openapi__tests__openapi_custom_extension.snap
@@ -0,0 +1,14 @@
+---
+source: utoipa/src/openapi.rs
+expression: api
+snapshot_kind: text
+---
+{
+  "openapi": "3.1.0",
+  "info": {
+    "title": "",
+    "version": ""
+  },
+  "paths": {},
+  "x-tagGroup": "anything that serializes to Json"
+}
diff --git a/utoipa/src/openapi/testdata/expected_openapi_minimal.json b/utoipa/src/snapshots/utoipa__openapi__tests__serialize_openapi_json_minimal_success.snap
similarity index 73%
rename from utoipa/src/openapi/testdata/expected_openapi_minimal.json
rename to utoipa/src/snapshots/utoipa__openapi__tests__serialize_openapi_json_minimal_success.snap
index ce3fccb..cbc69b7 100644
--- a/utoipa/src/openapi/testdata/expected_openapi_minimal.json
+++ b/utoipa/src/snapshots/utoipa__openapi__tests__serialize_openapi_json_minimal_success.snap
@@ -1,3 +1,8 @@
+---
+source: utoipa/src/openapi.rs
+expression: openapi
+snapshot_kind: text
+---
 {
   "openapi": "3.1.0",
   "info": {
@@ -10,4 +15,4 @@
     "version": "1.0.0"
   },
   "paths": {}
-}
\ No newline at end of file
+}
diff --git a/utoipa/src/openapi/testdata/expected_openapi_with_paths.json b/utoipa/src/snapshots/utoipa__openapi__tests__serialize_openapi_json_with_paths_success.snap
similarity index 87%
rename from utoipa/src/openapi/testdata/expected_openapi_with_paths.json
rename to utoipa/src/snapshots/utoipa__openapi__tests__serialize_openapi_json_with_paths_success.snap
index c18ab68..2db3e52 100644
--- a/utoipa/src/openapi/testdata/expected_openapi_with_paths.json
+++ b/utoipa/src/snapshots/utoipa__openapi__tests__serialize_openapi_json_with_paths_success.snap
@@ -1,3 +1,8 @@
+---
+source: utoipa/src/openapi.rs
+expression: openapi
+snapshot_kind: text
+---
 {
   "openapi": "3.1.0",
   "info": {
@@ -31,4 +36,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}