Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

128 lignes
5.4KB

  1. using System.Net;
  2. using System.Net.Http.Headers;
  3. using System.Net.Http.Json;
  4. namespace Campaign_Tracker.Server.Tests;
  5. public sealed class MunicipalityProfileControllerTests
  6. {
  7. // ── AC #1: profile created and saved with legacy link ────────────────────
  8. [Fact]
  9. public async Task CreateProfile_ValidJCode_Returns200WithCombinedView_AC1_AC2()
  10. {
  11. await using var factory = new AuthIntegrationTestFactory();
  12. using var client = factory.CreateClient();
  13. client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
  14. "Bearer", AuthIntegrationTestFactory.CreateToken("cs@example.test", "client-services"));
  15. var response = await client.PostAsJsonAsync("/api/municipalities/profiles", new
  16. {
  17. jCode = "FAIR01",
  18. displayName = "Fairview Borough Profile",
  19. });
  20. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  21. var body = await response.Content.ReadFromJsonAsync<MunicipalityProfileDto>();
  22. Assert.NotNull(body);
  23. Assert.Equal("FAIR01", body.JCode);
  24. Assert.Equal("Fairview Borough Profile", body.DisplayName);
  25. // AC #2: combined view includes resolved legacy name
  26. Assert.Equal("Fairview Borough", body.LegacyName);
  27. }
  28. // ── AC #2: list returns combined extension + legacy fields ────────────────
  29. [Fact]
  30. public async Task GetAllProfiles_ReturnsResolvedLegacyData_AC2()
  31. {
  32. await using var factory = new AuthIntegrationTestFactory();
  33. using var client = factory.CreateClient();
  34. client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
  35. "Bearer", AuthIntegrationTestFactory.CreateToken("cs@example.test", "client-services"));
  36. await client.PostAsJsonAsync("/api/municipalities/profiles", new { jCode = "LAKE02", displayName = (string?)null });
  37. var response = await client.GetAsync("/api/municipalities/profiles");
  38. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  39. var profiles = await response.Content.ReadFromJsonAsync<MunicipalityProfileDto[]>();
  40. Assert.NotNull(profiles);
  41. var lake = Assert.Single(profiles, p => p.JCode == "LAKE02");
  42. Assert.Equal("Lake Township", lake.LegacyName);
  43. }
  44. // ── AC #3: update audits the change (server-side; response includes actor) ─
  45. [Fact]
  46. public async Task UpdateProfile_ChangesDisplayName_Returns200_AC3()
  47. {
  48. await using var factory = new AuthIntegrationTestFactory();
  49. using var client = factory.CreateClient();
  50. client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
  51. "Bearer", AuthIntegrationTestFactory.CreateToken("cs@example.test", "client-services"));
  52. var created = await (await client.PostAsJsonAsync("/api/municipalities/profiles",
  53. new { jCode = "FAIR01", displayName = "Old Name" }))
  54. .Content.ReadFromJsonAsync<MunicipalityProfileDto>();
  55. var response = await client.PutAsJsonAsync(
  56. $"/api/municipalities/profiles/{created!.ProfileId}",
  57. new { displayName = "New Name" });
  58. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  59. var updated = await response.Content.ReadFromJsonAsync<MunicipalityProfileDto>();
  60. Assert.Equal("New Name", updated!.DisplayName);
  61. }
  62. // ── AC #4: invalid JCode rejected before save ─────────────────────────────
  63. [Fact]
  64. public async Task CreateProfile_InvalidJCode_Returns422WithDescription_AC4()
  65. {
  66. await using var factory = new AuthIntegrationTestFactory();
  67. using var client = factory.CreateClient();
  68. client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
  69. "Bearer", AuthIntegrationTestFactory.CreateToken("cs@example.test", "client-services"));
  70. var response = await client.PostAsJsonAsync("/api/municipalities/profiles", new
  71. {
  72. jCode = "DOESNOTEXIST",
  73. displayName = (string?)null,
  74. });
  75. Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode);
  76. var body = await response.Content.ReadFromJsonAsync<MunicipalityProfileProblemDto>();
  77. Assert.NotNull(body);
  78. Assert.Contains("DOESNOTEXIST", body.Error);
  79. }
  80. // ── Authorization: non-recognized role gets 403 ───────────────────────────
  81. [Fact]
  82. public async Task CreateProfile_NoToken_Returns401()
  83. {
  84. await using var factory = new AuthIntegrationTestFactory();
  85. using var client = factory.CreateClient();
  86. var response = await client.PostAsJsonAsync("/api/municipalities/profiles",
  87. new { jCode = "FAIR01", displayName = (string?)null });
  88. Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
  89. }
  90. // ── Local DTOs for deserialization ────────────────────────────────────────
  91. private sealed record MunicipalityProfileDto(
  92. string ProfileId,
  93. string JCode,
  94. string? DisplayName,
  95. string UpdatedAt,
  96. string UpdatedBy,
  97. string? LegacyName,
  98. string? LegacyMailingAddress,
  99. string? LegacyCityStateZip);
  100. private sealed record MunicipalityProfileProblemDto(string Error);
  101. }

Powered by TurnKey Linux.