using System.Net; using System.Text.Json; using JdeScoping.Client.Services; using JdeScoping.Core.ApiContracts; using JdeScoping.Core.ViewModels; using RichardSzalay.MockHttp; using Shouldly; namespace JdeScoping.Client.Tests.Services; public class LookupApiClientTests { private readonly MockHttpMessageHandler _mockHttp; private readonly LookupApiClient _client; private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; public LookupApiClientTests() { _mockHttp = new MockHttpMessageHandler(); var httpClient = new HttpClient(_mockHttp) { BaseAddress = new Uri("http://localhost/") }; _client = new LookupApiClient(httpClient); } // Route verification tests [Fact] public async Task FindItemsAsync_CallsCorrectRoute_WithQuery() { // Arrange var query = "TEST123"; var expectedUrl = $"http://localhost/{ApiRoutes.Lookup.FindItems(query)}"; var request = _mockHttp.Expect(HttpMethod.Get, expectedUrl) .Respond("application/json", "[]"); // Act await _client.FindItemsAsync(query); // Assert _mockHttp.GetMatchCount(request).ShouldBe(1); } [Fact] public async Task FindProfitCentersAsync_CallsCorrectRoute() { // Arrange var query = "PC1"; var request = _mockHttp.Expect(HttpMethod.Get, $"http://localhost/{ApiRoutes.Lookup.FindProfitCenters(query)}") .Respond("application/json", "[]"); // Act await _client.FindProfitCentersAsync(query); // Assert _mockHttp.GetMatchCount(request).ShouldBe(1); } [Fact] public async Task FindWorkCentersAsync_CallsCorrectRoute() { // Arrange var query = "WC1"; var request = _mockHttp.Expect(HttpMethod.Get, $"http://localhost/{ApiRoutes.Lookup.FindWorkCenters(query)}") .Respond("application/json", "[]"); // Act await _client.FindWorkCentersAsync(query); // Assert _mockHttp.GetMatchCount(request).ShouldBe(1); } [Fact] public async Task FindOperatorsAsync_CallsCorrectRoute() { // Arrange var query = "John"; var request = _mockHttp.Expect(HttpMethod.Get, $"http://localhost/{ApiRoutes.Lookup.FindOperators(query)}") .Respond("application/json", "[]"); // Act await _client.FindOperatorsAsync(query); // Assert _mockHttp.GetMatchCount(request).ShouldBe(1); } // Query string encoding tests [Fact] public async Task FindItemsAsync_EncodesSpecialCharacters_InQueryString() { // Arrange - query with special characters that need URL encoding var query = "TEST&ITEM=1"; var expectedUrl = $"http://localhost/{ApiRoutes.Lookup.FindItems(query)}"; // The URL should have encoded & as %26 and = as %3D expectedUrl.ShouldContain("%26"); expectedUrl.ShouldContain("%3D"); var request = _mockHttp.Expect(HttpMethod.Get, expectedUrl) .Respond("application/json", "[]"); // Act await _client.FindItemsAsync(query); // Assert _mockHttp.GetMatchCount(request).ShouldBe(1); } [Fact] public async Task FindItemsAsync_EncodesSpaces_InQueryString() { // Arrange - query with spaces var query = "TEST ITEM"; var expectedUrl = $"http://localhost/{ApiRoutes.Lookup.FindItems(query)}"; // The URL should have encoded space as %20 expectedUrl.ShouldContain("%20"); var request = _mockHttp.Expect(HttpMethod.Get, expectedUrl) .Respond("application/json", "[]"); // Act await _client.FindItemsAsync(query); // Assert _mockHttp.GetMatchCount(request).ShouldBe(1); } // Success tests [Fact] public async Task FindItemsAsync_Success_ReturnsItemList() { // Arrange var items = new List { new() { ItemNumber = "ITEM1", Description = "Item One" }, new() { ItemNumber = "ITEM2", Description = "Item Two" } }; _mockHttp.When(HttpMethod.Get, "*") .Respond("application/json", JsonSerializer.Serialize(items, JsonOptions)); // Act var result = await _client.FindItemsAsync("ITEM"); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.Count.ShouldBe(2); result.Value[0].ItemNumber.ShouldBe("ITEM1"); } [Fact] public async Task FindOperatorsAsync_Success_ReturnsUserList() { // Arrange var users = new List { new() { UserId = "USER1", FullName = "John Doe" } }; _mockHttp.When(HttpMethod.Get, "*") .Respond("application/json", JsonSerializer.Serialize(users, JsonOptions)); // Act var result = await _client.FindOperatorsAsync("John"); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.Count.ShouldBe(1); } [Fact] public async Task FindProfitCentersAsync_Success_ReturnsProfitCenterList() { // Arrange var profitCenters = new List { new() { Code = "PC001", Description = "Profit Center One" }, new() { Code = "PC002", Description = "Profit Center Two" } }; _mockHttp.When(HttpMethod.Get, "*") .Respond("application/json", JsonSerializer.Serialize(profitCenters, JsonOptions)); // Act var result = await _client.FindProfitCentersAsync("PC"); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.Count.ShouldBe(2); result.Value[0].Code.ShouldBe("PC001"); } [Fact] public async Task FindWorkCentersAsync_Success_ReturnsWorkCenterList() { // Arrange var workCenters = new List { new() { Code = "WC001", Description = "Work Center One" } }; _mockHttp.When(HttpMethod.Get, "*") .Respond("application/json", JsonSerializer.Serialize(workCenters, JsonOptions)); // Act var result = await _client.FindWorkCentersAsync("WC"); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.Count.ShouldBe(1); result.Value[0].Code.ShouldBe("WC001"); } // Representative error test [Fact] public async Task FindItemsAsync_500_ReturnsError() { // Arrange _mockHttp.When(HttpMethod.Get, "*") .Respond(HttpStatusCode.InternalServerError, "text/plain", "Internal Server Error"); // Act var result = await _client.FindItemsAsync("test"); // Assert result.IsError.ShouldBeTrue(); result.Error.StatusCode.ShouldBe(500); } }