using Kitchen.Service.Application.Ports; using Kitchen.Service.Application.UseCases; using Kitchen.Service.Contracts.Requests; namespace Kitchen.Service.Application.UnitTests; public class KitchenWorkflowUseCasesTests { private readonly InMemoryKitchenWorkItemStorePort workItemStore = new(); private readonly InMemoryRestaurantLifecycleSyncPort restaurantLifecycle = new(); private readonly DefaultKitchenWorkflowPort workflowPort; public KitchenWorkflowUseCasesTests() { workflowPort = new DefaultKitchenWorkflowPort(workItemStore, restaurantLifecycle); } [Fact] public async Task GetKitchenBoardUseCase_ReturnsLanesAndStations() { var useCase = new GetKitchenBoardUseCase(workflowPort); var response = await useCase.HandleAsync(new GetKitchenBoardRequest("demo-context"), CancellationToken.None); Assert.Equal("demo-context", response.ContextId); Assert.NotEmpty(response.Lanes); Assert.NotEmpty(response.AvailableStations); Assert.Contains(response.Lanes, lane => lane.Lane == "queued"); } [Fact] public async Task ClaimKitchenWorkItemUseCase_ReturnsClaimedResponse() { var useCase = new ClaimKitchenWorkItemUseCase(workflowPort); var response = await useCase.HandleAsync( new ClaimKitchenWorkItemRequest("demo-context", "WK-1001", "chef-maya"), CancellationToken.None); var updated = await workItemStore.GetAsync("demo-context", "WK-1001", CancellationToken.None); Assert.True(response.Claimed); Assert.Equal("chef-maya", response.ClaimedBy); Assert.Equal("chef-maya", updated!.ClaimedBy); } [Fact] public async Task UpdateKitchenPriorityUseCase_NormalizesPriority() { var useCase = new UpdateKitchenPriorityUseCase(workflowPort); var response = await useCase.HandleAsync( new UpdateKitchenPriorityRequest("demo-context", "WK-1001", 0, "expo-noah"), CancellationToken.None); var updated = await workItemStore.GetAsync("demo-context", "WK-1001", CancellationToken.None); Assert.Equal(1, response.Priority); Assert.Equal(1, updated!.Priority); } [Fact] public async Task TransitionKitchenOrderStateUseCase_UpdatesKitchenAndRestaurantFlow() { var useCase = new TransitionKitchenOrderStateUseCase(workflowPort); var response = await useCase.HandleAsync( new TransitionKitchenOrderStateRequest("ORD-1001", "KT-1001", "Preparing", "chef-maya"), CancellationToken.None); var updatedWorkItem = await workItemStore.GetAsync("demo-context", "WK-1001", CancellationToken.None); var updatedOrder = await restaurantLifecycle.GetOrderAsync("demo-context", "ORD-1001", CancellationToken.None); Assert.True(response.Applied); Assert.Equal("Queued", response.PreviousState); Assert.Equal("Preparing", response.CurrentState); Assert.Equal("Preparing", updatedWorkItem!.State); Assert.Equal("Preparing", updatedOrder!.OrderState); Assert.True(updatedOrder.HasKitchenTicket); } [Fact] public async Task TransitionKitchenOrderStateUseCase_MarksOrderServedWhenKitchenDelivers() { var useCase = new TransitionKitchenOrderStateUseCase(workflowPort); var response = await useCase.HandleAsync( new TransitionKitchenOrderStateRequest("ORD-1003", "KT-1003", "Delivered", "expo-noah"), CancellationToken.None); var updatedWorkItem = await workItemStore.GetAsync("demo-context", "WK-1003", CancellationToken.None); var updatedOrder = await restaurantLifecycle.GetOrderAsync("demo-context", "ORD-1003", CancellationToken.None); Assert.True(response.Applied); Assert.Equal("ReadyForPickup", response.PreviousState); Assert.Equal("Delivered", response.CurrentState); Assert.Equal("Delivered", updatedWorkItem!.State); Assert.Equal("Served", updatedOrder!.OrderState); } }