25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

191 satır
7.7KB

  1. using System.Net;
  2. using System.Net.Http.Headers;
  3. using System.Net.Http.Json;
  4. using Campaign_Tracker.Server.Audit;
  5. using Microsoft.Extensions.DependencyInjection;
  6. namespace Campaign_Tracker.Server.Tests;
  7. public sealed class MunicipalityContactControllerTests
  8. {
  9. [Fact]
  10. public async Task AddContact_ValidRequest_Returns201WithContactTypeAndDetails_AC1()
  11. {
  12. await using var factory = new AuthIntegrationTestFactory();
  13. using var client = CreateClient(factory);
  14. var profile = await CreateProfile(client);
  15. var response = await client.PostAsJsonAsync(
  16. $"/api/municipalities/{profile.ProfileId}/contacts",
  17. new
  18. {
  19. contactType = "Primary",
  20. name = "Ada Clerk",
  21. roleTitle = "Town Clerk",
  22. phone = "555-0100",
  23. email = "ada@example.test",
  24. });
  25. Assert.Equal(HttpStatusCode.Created, response.StatusCode);
  26. var body = await response.Content.ReadFromJsonAsync<MunicipalityContactDto>();
  27. Assert.NotNull(body);
  28. Assert.Equal("Primary", body.ContactType);
  29. Assert.Equal("Ada Clerk", body.Name);
  30. Assert.Equal("Town Clerk", body.RoleTitle);
  31. Assert.Equal("555-0100", body.Phone);
  32. Assert.Equal("ada@example.test", body.Email);
  33. }
  34. [Fact]
  35. public async Task GetContacts_DisplaysPrimaryAndSecondaryDesignations_AC2()
  36. {
  37. await using var factory = new AuthIntegrationTestFactory();
  38. using var client = CreateClient(factory);
  39. var profile = await CreateProfile(client);
  40. await client.PostAsJsonAsync(
  41. $"/api/municipalities/{profile.ProfileId}/contacts",
  42. new { contactType = "Secondary", name = "Backup Clerk" });
  43. await client.PostAsJsonAsync(
  44. $"/api/municipalities/{profile.ProfileId}/contacts",
  45. new { contactType = "Primary", name = "Main Clerk" });
  46. var response = await client.GetAsync($"/api/municipalities/{profile.ProfileId}/contacts");
  47. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  48. var body = await response.Content.ReadFromJsonAsync<MunicipalityContactDto[]>();
  49. Assert.NotNull(body);
  50. Assert.Equal(["Primary", "Secondary"], body.Select(c => c.ContactType).ToArray());
  51. }
  52. [Fact]
  53. public async Task UpdateAndDeleteContact_RecordAuditEvents_AC3()
  54. {
  55. await using var factory = new AuthIntegrationTestFactory();
  56. using var client = CreateClient(factory);
  57. var profile = await CreateProfile(client);
  58. var created = await (await client.PostAsJsonAsync(
  59. $"/api/municipalities/{profile.ProfileId}/contacts",
  60. new { contactType = "Primary", name = "Ada Clerk" }))
  61. .Content.ReadFromJsonAsync<MunicipalityContactDto>();
  62. var updateResponse = await client.PutAsJsonAsync(
  63. $"/api/municipalities/{profile.ProfileId}/contacts/{created!.ContactId}",
  64. new { contactType = "Secondary", name = "Ada Updated", roleTitle = "Manager" });
  65. var deleteResponse = await client.DeleteAsync(
  66. $"/api/municipalities/{profile.ProfileId}/contacts/{created.ContactId}");
  67. Assert.Equal(HttpStatusCode.OK, updateResponse.StatusCode);
  68. Assert.Equal(HttpStatusCode.NoContent, deleteResponse.StatusCode);
  69. var auditService = factory.Services.GetRequiredService<IAuditService>();
  70. var events = auditService.GetRecent();
  71. Assert.Contains(events, e =>
  72. e.EventType == "MUNICIPALITY_CONTACT_UPDATED" &&
  73. e.ActorIdentity == "cs@example.test");
  74. Assert.Contains(events, e =>
  75. e.EventType == "MUNICIPALITY_CONTACT_DELETED" &&
  76. e.ActorIdentity == "cs@example.test");
  77. }
  78. [Theory]
  79. [InlineData("", "Primary", "Name is required.")]
  80. [InlineData("Ada Clerk", "", "Contact type is required.")]
  81. public async Task AddContact_MissingRequiredFields_Returns422Problem_AC4(
  82. string name,
  83. string contactType,
  84. string expectedError)
  85. {
  86. await using var factory = new AuthIntegrationTestFactory();
  87. using var client = CreateClient(factory);
  88. var profile = await CreateProfile(client);
  89. var response = await client.PostAsJsonAsync(
  90. $"/api/municipalities/{profile.ProfileId}/contacts",
  91. new { contactType, name });
  92. Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode);
  93. var problem = await response.Content.ReadFromJsonAsync<MunicipalityContactProblemDto>();
  94. Assert.NotNull(problem);
  95. Assert.Equal(expectedError, problem.Error);
  96. }
  97. [Fact]
  98. public async Task AddContact_UnknownProfile_Returns404()
  99. {
  100. await using var factory = new AuthIntegrationTestFactory();
  101. using var client = CreateClient(factory);
  102. var response = await client.PostAsJsonAsync(
  103. "/api/municipalities/does-not-exist/contacts",
  104. new { contactType = "Primary", name = "Ada Clerk" });
  105. Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
  106. }
  107. [Fact]
  108. public async Task ContactRoutes_RejectContactFromDifferentProfile()
  109. {
  110. await using var factory = new AuthIntegrationTestFactory();
  111. using var client = CreateClient(factory);
  112. var profileA = await CreateProfile(client, "FAIR01");
  113. var profileB = await CreateProfile(client, "LAKE02");
  114. var created = await (await client.PostAsJsonAsync(
  115. $"/api/municipalities/{profileA.ProfileId}/contacts",
  116. new { contactType = "Primary", name = "Ada Clerk" }))
  117. .Content.ReadFromJsonAsync<MunicipalityContactDto>();
  118. var getResponse = await client.GetAsync(
  119. $"/api/municipalities/{profileB.ProfileId}/contacts/{created!.ContactId}");
  120. var updateResponse = await client.PutAsJsonAsync(
  121. $"/api/municipalities/{profileB.ProfileId}/contacts/{created.ContactId}",
  122. new { contactType = "Secondary", name = "Wrong Profile" });
  123. var deleteResponse = await client.DeleteAsync(
  124. $"/api/municipalities/{profileB.ProfileId}/contacts/{created.ContactId}");
  125. Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode);
  126. Assert.Equal(HttpStatusCode.NotFound, updateResponse.StatusCode);
  127. Assert.Equal(HttpStatusCode.NotFound, deleteResponse.StatusCode);
  128. var originalProfileResponse = await client.GetAsync(
  129. $"/api/municipalities/{profileA.ProfileId}/contacts/{created.ContactId}");
  130. Assert.Equal(HttpStatusCode.OK, originalProfileResponse.StatusCode);
  131. }
  132. private static HttpClient CreateClient(AuthIntegrationTestFactory factory)
  133. {
  134. var client = factory.CreateClient();
  135. client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
  136. "Bearer", AuthIntegrationTestFactory.CreateToken("cs@example.test", "client-services"));
  137. return client;
  138. }
  139. private static async Task<MunicipalityProfileDto> CreateProfile(
  140. HttpClient client,
  141. string jCode = "FAIR01")
  142. {
  143. var created = await (await client.PostAsJsonAsync("/api/municipalities/profiles", new
  144. {
  145. jCode,
  146. displayName = $"{jCode} Profile",
  147. })).Content.ReadFromJsonAsync<MunicipalityProfileDto>();
  148. Assert.NotNull(created);
  149. return created;
  150. }
  151. private sealed record MunicipalityProfileDto(string ProfileId);
  152. private sealed record MunicipalityContactDto(
  153. string ContactId,
  154. string ProfileId,
  155. string ContactType,
  156. string Name,
  157. string? RoleTitle,
  158. string? Phone,
  159. string? Email,
  160. string UpdatedAt,
  161. string UpdatedBy);
  162. private sealed record MunicipalityContactProblemDto(string Error);
  163. }

Powered by TurnKey Linux.