using Operations.Service.Application.Ports; using Operations.Service.Application.UseCases; using Operations.Service.Contracts.Requests; namespace Operations.Service.Application.UnitTests; public class OperationsWorkflowUseCasesTests { private readonly InMemoryRestaurantLifecycleStorePort lifecycleStore = new(); private readonly DefaultOperationsWorkflowPort workflowPort; public OperationsWorkflowUseCasesTests() { workflowPort = new DefaultOperationsWorkflowPort(lifecycleStore); } [Fact] public async Task GetWaiterAssignmentsUseCase_ReturnsAssignmentsAndActivity() { var useCase = new GetWaiterAssignmentsUseCase(workflowPort); var response = await useCase.HandleAsync(new GetWaiterAssignmentsRequest("demo-context"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotEmpty(response.Assignments); Assert.NotEmpty(response.RecentActivity); Assert.Contains(response.Assignments, assignment => assignment.Status == "ready-for-check"); } [Fact] public async Task SubmitRestaurantOrderUseCase_WhenRequestValid_PersistsAcceptedOrder() { var useCase = new SubmitRestaurantOrderUseCase(workflowPort); var response = await useCase.HandleAsync( new SubmitRestaurantOrderRequest("demo-context", "ORD-101", "T-12", 3), CancellationToken.None); var persisted = await lifecycleStore.GetOrderAsync("demo-context", "ORD-101", CancellationToken.None); Assert.True(response.Accepted); Assert.Equal("accepted", response.Status); Assert.NotNull(persisted); Assert.Equal("Accepted", persisted!.OrderState); } [Fact] public async Task GetCustomerOrderStatusUseCase_ReturnsOrdersFromSharedLifecycleStore() { var useCase = new GetCustomerOrderStatusUseCase(workflowPort); var response = await useCase.HandleAsync(new GetCustomerOrderStatusRequest("demo-context"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotEmpty(response.Orders); Assert.NotEmpty(response.RecentEvents); Assert.Contains(response.Orders, order => order.OrderId == "ORD-1001"); } [Fact] public async Task GetCustomerOrderDetailUseCase_ReturnsSpecificLifecycleOrder() { var useCase = new GetCustomerOrderDetailUseCase(workflowPort); var response = await useCase.HandleAsync( new GetCustomerOrderDetailRequest("demo-context", "ORD-1001"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotNull(response.Order); Assert.Equal("ORD-1001", response.Order!.OrderId); Assert.NotEmpty(response.RecentEvents); } [Fact] public async Task GetCustomerOrderHistoryUseCase_ReturnsLifecycleBackedHistory() { var useCase = new GetCustomerOrderHistoryUseCase(workflowPort); var response = await useCase.HandleAsync( new GetCustomerOrderHistoryRequest("demo-context"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotEmpty(response.Orders); Assert.NotEmpty(response.RecentEvents); Assert.Contains("lifecycle-backed history", response.Summary); } [Fact] public async Task GetPosTransactionSummaryUseCase_ReturnsOnlyPayableChecks() { var useCase = new GetPosTransactionSummaryUseCase(workflowPort); var response = await useCase.HandleAsync(new GetPosTransactionSummaryRequest("demo-context"), CancellationToken.None); Assert.Equal("USD", response.Currency); Assert.NotEmpty(response.RecentPayments); Assert.All(response.RecentPayments, payment => Assert.Equal("check", payment.PaymentMethod)); } [Fact] public async Task GetPosTransactionDetailUseCase_ReturnsLifecycleBackedCheck() { var useCase = new GetPosTransactionDetailUseCase(workflowPort); var response = await useCase.HandleAsync( new GetPosTransactionDetailRequest("demo-context", "CHK-1002"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotNull(response.Transaction); Assert.Equal("CHK-1002", response.Transaction!.TransactionId); Assert.Equal("awaiting-payment", response.Transaction.Status); } [Fact] public async Task CapturePosPaymentUseCase_WhenOrderServed_ReturnsCapturedStatus() { var useCase = new CapturePosPaymentUseCase(workflowPort); var response = await useCase.HandleAsync( new CapturePosPaymentRequest("demo-context", "CHK-1002", 37.50m, "USD", "card"), CancellationToken.None); var updated = await lifecycleStore.GetOrderAsync("demo-context", "ORD-1002", CancellationToken.None); Assert.True(response.Succeeded); Assert.Equal("captured", response.Status); Assert.NotNull(updated); Assert.Equal("Paid", updated!.CheckState); Assert.Equal(0m, updated.OutstandingBalance); } [Fact] public async Task CapturePosPaymentUseCase_WhenOrderNotServed_ReturnsBlockedStatus() { var useCase = new CapturePosPaymentUseCase(workflowPort); var response = await useCase.HandleAsync( new CapturePosPaymentRequest("demo-context", "ORD-1001", 12m, "USD", "card"), CancellationToken.None); Assert.False(response.Succeeded); Assert.Equal("blocked", response.Status); } [Fact] public async Task GetRestaurantAdminConfigUseCase_ReturnsFlagsWindowsAndChanges() { var useCase = new GetRestaurantAdminConfigUseCase(workflowPort); var response = await useCase.HandleAsync(new GetRestaurantAdminConfigRequest("demo-context"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotEmpty(response.FeatureFlags); Assert.NotEmpty(response.ServiceWindows); Assert.NotEmpty(response.RecentChanges); } [Fact] public async Task SetServiceWindowUseCase_WhenRequestValid_ReturnsAppliedResponse() { var useCase = new SetServiceWindowUseCase(workflowPort); var response = await useCase.HandleAsync( new SetServiceWindowRequest("demo-context", 1, "08:00:00", "22:00:00", "admin-operator"), CancellationToken.None); Assert.True(response.Applied); Assert.Equal(1, response.ServiceWindow.DayOfWeek); } }