Files
Joseph Doherty d06d5f27e2 test: add LookupApiClientTests with route and encoding tests
- Route verification tests for all 4 methods (FindItems, FindProfitCenters,
  FindWorkCenters, FindOperators)
- Query string encoding tests verifying special characters (&, =) and spaces
  are properly URL-encoded
- Success tests for all lookup methods verifying deserialization
- Representative error test for 500 status code
2026-01-06 11:29:46 -05:00

231 lines
7.0 KiB
C#

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<ItemViewModel>
{
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<JdeUserViewModel>
{
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<ProfitCenterViewModel>
{
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<WorkCenterViewModel>
{
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);
}
}