using System.Net; using System.Text; using Customer.Orders.Bff.Application.Adapters; using Customer.Orders.Bff.Contracts.Requests; namespace Customer.Orders.Bff.Application.UnitTests; public sealed class OperationsCustomerOrdersServiceClientTests { [Fact] public async Task FetchStatusAsync_MapsOrdersAndEvents() { var adapter = new OperationsCustomerOrdersServiceClient(CreateClient(StatusPayload)); var response = await adapter.FetchStatusAsync(new GetCustomerOrderStatusRequest("demo-context"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotEmpty(response.Orders); Assert.NotEmpty(response.RecentEvents); } [Fact] public async Task FetchDetailAsync_ReturnsMatchingOrderWhenPresent() { var adapter = new OperationsCustomerOrdersServiceClient(CreateClient(StatusPayload)); var response = await adapter.FetchDetailAsync(new GetCustomerOrderDetailRequest("demo-context", "ORD-1001"), CancellationToken.None); Assert.NotNull(response.Order); Assert.Equal("ORD-1001", response.Order!.OrderId); Assert.Contains("preparing", response.Summary, StringComparison.OrdinalIgnoreCase); } [Fact] public async Task FetchHistoryAsync_ReturnsProjectedHistorySnapshot() { var adapter = new OperationsCustomerOrdersServiceClient(CreateClient(StatusPayload)); var response = await adapter.FetchHistoryAsync(new GetCustomerOrderStatusRequest("demo-context"), CancellationToken.None); Assert.Equal(2, response.Orders.Count); Assert.Equal(2, response.RecentEvents.Count); } [Fact] public async Task SubmitOrderAsync_MapsSharedLifecycleAcceptanceUsingItemCount() { var adapter = new OperationsCustomerOrdersServiceClient(CreateClient(""" { "contextId": "demo-context", "orderId": "ORD-1009", "accepted": true, "summary": "Order ORD-1009 was accepted and is ready for kitchen dispatch.", "status": "accepted", "submittedAtUtc": "2026-03-31T12:30:00Z" } """)); var response = await adapter.SubmitOrderAsync( new SubmitCustomerOrderRequest("demo-context", "ORD-1009", "T-18", 4, ["ITEM-101", "ITEM-202", "ITEM-303"]), CancellationToken.None); Assert.True(response.Accepted); Assert.Equal("accepted", response.Status); Assert.Contains("kitchen dispatch", response.Summary); } private static HttpClient CreateClient(string json) { return new HttpClient(new StubHttpMessageHandler(json)) { BaseAddress = new Uri("http://operations-service:8080/") }; } private sealed class StubHttpMessageHandler(string json) : HttpMessageHandler { protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(json, Encoding.UTF8, "application/json") }); } } private const string StatusPayload = """ { "contextId": "demo-context", "summary": "2 recent customer orders are visible for the active context.", "orders": [ { "orderId": "ORD-1001", "tableId": "T-08", "status": "preparing", "guestCount": 2, "itemIds": [ "ITEM-101", "ITEM-202" ] }, { "orderId": "ORD-1002", "tableId": "T-15", "status": "ready", "guestCount": 4, "itemIds": [ "ITEM-301", "ITEM-404", "ITEM-405" ] } ], "recentEvents": [ "Order ORD-1001 moved to preparing at the kitchen hot-line station.", "Order ORD-1002 is ready for table pickup." ] } """; }