using System.Text.Json; using Yavsc.Blogspot; using Yavsc.Models.Blog; namespace Yavsc.Blogs.Tests; /// /// Wire-shape tests pinning that /// is carried on the JSON the blog API list endpoint emits. /// /// The blog API host (Yavsc.Blogs/Program.cs) serialises /// with System.Text.Json (the .AddControllers() default — no /// AddNewtonsoftJson), and BlogApiController.GetBlogspot /// returns IEnumerable<IBlogPost>. System.Text.Json emits /// only the members of the declared type, so a property that /// exists solely on the concrete BlogPost entity is dropped from /// the payload. IsPublished used to be one such property: it was /// on BlogPost and BlogPostDto but not on /// , so the list response omitted it and PostIt /// read IsPublished == false for every post — including /// published ones. /// /// These tests reproduce that serialisation path directly /// (declared type IEnumerable<IBlogPost> through /// ) and assert /// isPublished survives the round trip. They live in /// Yavsc.Blogs.Tests — the assembly that owns the blog API /// contract — so a regression at the wire boundary is caught here, /// where it manifested in production (PostIt showing a published /// post's status as false). /// public sealed class IBlogPostWireShapeTests { private static readonly JsonSerializerOptions WebDefaults = new(JsonSerializerDefaults.Web); [Fact] public void IsPublished_is_emitted_when_list_is_serialised_as_IEnumerable_IBlogPost() { var post = new BlogPost { Id = 13, Title = "Published", AuthorId = "alice", Article = "x", }; post.IsPublished = true; // Declared type mirrors GetBlogspot's return: IEnumerable. IEnumerable list = new List { post }; // Serialize with the DECLARED type, the way ASP.NET Core's // SystemTextJsonOutputFormatter hands context.ObjectType (the // action return type) to JsonSerializer.Serialize. var json = JsonSerializer.Serialize(list, typeof(IEnumerable), WebDefaults); using var doc = JsonDocument.Parse(json); var element = doc.RootElement[0]; // Web defaults use camelCase, so the property is "isPublished". Assert.True(element.TryGetProperty("isPublished", out var isPublished), $"isPublished was dropped from the list payload. JSON: {json}"); Assert.True(isPublished.GetBoolean()); } [Fact] public void IsPublished_round_trips_through_BlogPostDto_on_the_client() { // The shape the client (PostIt) receives and deserialises with // PropertyNameCaseInsensitive = true (cf. YavscApiClient). var json = """ [{ "id": 13, "title": "Published", "article": "x", "authorId": "alice", "isPublished": true }] """; var posts = JsonSerializer.Deserialize>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!; var post = Assert.Single(posts); Assert.True(post.IsPublished); } }