using System.Net; using System.Text; using Pos.Transactions.Bff.Application.Adapters; using Pos.Transactions.Bff.Contracts.Requests; namespace Pos.Transactions.Bff.Application.UnitTests; public sealed class OperationsPosTransactionsServiceClientTests { [Fact] public async Task FetchSummaryAsync_MapsBalanceCurrencyAndPayments() { var adapter = new OperationsPosTransactionsServiceClient(CreateClient(SummaryPayload)); var response = await adapter.FetchSummaryAsync(new GetPosTransactionSummaryRequest("demo-context"), CancellationToken.None); Assert.Equal(37.50m, response.OpenBalance); Assert.Equal("USD", response.Currency); Assert.Equal(2, response.RecentPayments.Count); } [Fact] public async Task FetchDetailAsync_ReturnsMatchingTransactionWhenPresent() { var adapter = new OperationsPosTransactionsServiceClient(CreateClient(SummaryPayload)); var response = await adapter.FetchDetailAsync(new GetPosTransactionDetailRequest("demo-context", "CHK-1002"), CancellationToken.None); Assert.NotNull(response.Transaction); Assert.Equal("CHK-1002", response.Transaction!.TransactionId); Assert.Equal("awaiting-payment", response.Transaction.Status); } [Fact] public async Task FetchRecentPaymentsAsync_ReturnsProjectedPaymentHistory() { var adapter = new OperationsPosTransactionsServiceClient(CreateClient(SummaryPayload)); var response = await adapter.FetchRecentPaymentsAsync(new GetPosTransactionSummaryRequest("demo-context"), CancellationToken.None); Assert.Equal(2, response.RecentPayments.Count); } [Fact] public async Task CapturePaymentAsync_MapsCaptureWorkflowPayload() { var adapter = new OperationsPosTransactionsServiceClient(CreateClient(""" { "contextId": "demo-context", "transactionId": "POS-9003", "succeeded": true, "summary": "Captured 19.95 USD using card.", "status": "captured", "capturedAtUtc": "2026-03-31T14:05:00Z" } """)); var response = await adapter.CapturePaymentAsync( new CapturePosPaymentRequest("demo-context", "POS-9003", 19.95m, "USD", "card"), CancellationToken.None); Assert.True(response.Succeeded); Assert.Equal("captured", response.Status); } 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 SummaryPayload = """ { "contextId": "demo-context", "summary": "2 payable checks are waiting for POS capture.", "openBalance": 37.50, "currency": "USD", "recentPayments": [ { "transactionId": "CHK-1002", "paymentMethod": "check", "amount": 25.50, "currency": "USD", "status": "awaiting-payment", "capturedAtUtc": "2026-03-31T13:30:00Z" }, { "transactionId": "CHK-1003", "paymentMethod": "check", "amount": 12.00, "currency": "USD", "status": "partial-payment", "capturedAtUtc": "2026-03-31T13:42:00Z" } ] } """; }