kitchen-ops-bff/tests/Kitchen.Ops.Bff.Application.UnitTests/KitchenWorkflowServiceClientTests.cs
2026-03-31 20:21:41 -06:00

150 lines
4.8 KiB
C#

using System.Net;
using System.Text;
using Kitchen.Ops.Bff.Application.Adapters;
using Kitchen.Ops.Bff.Contracts.Requests;
namespace Kitchen.Ops.Bff.Application.UnitTests;
public sealed class KitchenWorkflowServiceClientTests
{
[Fact]
public async Task FetchBoardAsync_MapsBoardLanesAndStations()
{
var adapter = new KitchenWorkflowServiceClient(CreateClient(BoardPayload));
var response = await adapter.FetchBoardAsync(new GetKitchenOpsBoardRequest("demo-context"), CancellationToken.None);
Assert.NotEmpty(response.Lanes);
Assert.NotEmpty(response.AvailableStations);
}
[Fact]
public async Task ClaimWorkItemAsync_MapsClaimResponse()
{
var adapter = new KitchenWorkflowServiceClient(CreateClient("""
{
"contextId": "demo-context",
"workItemId": "WK-1001",
"claimed": true,
"claimedBy": "chef-maya",
"message": "Work item WK-1001 claimed by chef-maya."
}
"""));
var response = await adapter.ClaimWorkItemAsync(
new ClaimKitchenWorkItemRequest("demo-context", "WK-1001", "chef-maya"),
CancellationToken.None);
Assert.True(response.Claimed);
Assert.Equal("chef-maya", response.ClaimedBy);
}
[Fact]
public async Task ReleaseWorkItemAsync_ProjectsReleaseMessage()
{
var adapter = new KitchenWorkflowServiceClient(CreateClient("""
{
"contextId": "demo-context",
"workItemId": "WK-1001",
"claimed": true,
"claimedBy": "chef-maya",
"message": "Work item WK-1001 claimed by chef-maya."
}
"""));
var response = await adapter.ReleaseWorkItemAsync(
new ReleaseKitchenWorkItemRequest("demo-context", "WK-1001", "chef-maya"),
CancellationToken.None);
Assert.True(response.Released);
Assert.Contains("release requested", response.Message);
}
[Fact]
public async Task TransitionWorkItemAsync_MapsTransitionResponse()
{
var adapter = new KitchenWorkflowServiceClient(CreateClient("""
{
"orderId": "ORD-1001",
"ticketId": "KT-1001",
"previousState": "Queued",
"currentState": "Preparing",
"applied": true,
"rejectionReason": null
}
"""));
var response = await adapter.TransitionWorkItemAsync(
new TransitionKitchenWorkItemRequest("ORD-1001", "KT-1001", "Cooking", "chef-maya", "demo-context"),
CancellationToken.None);
Assert.True(response.Transitioned);
Assert.Equal("Cooking", response.CurrentState);
}
[Fact]
public async Task SetOrderPriorityAsync_MapsPriorityResponse()
{
var adapter = new KitchenWorkflowServiceClient(CreateClient("""
{
"contextId": "demo-context",
"workItemId": "WK-1001",
"priority": 5,
"message": "Priority for WK-1001 updated to 5 by chef-maya."
}
"""));
var response = await adapter.SetOrderPriorityAsync(
new SetKitchenOrderPriorityRequest("demo-context", "WK-1001", 5, "chef-maya"),
CancellationToken.None);
Assert.True(response.Updated);
Assert.Equal(5, response.Priority);
}
private static HttpClient CreateClient(string json)
{
return new HttpClient(new StubHttpMessageHandler(json))
{
BaseAddress = new Uri("http://kitchen-service:8080/")
};
}
private sealed class StubHttpMessageHandler(string json) : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
});
}
}
private const string BoardPayload = """
{
"contextId": "demo-context",
"summary": "Kitchen board now reflects persisted tickets linked to shared restaurant orders.",
"lanes": [
{
"lane": "queued",
"items": [
{
"workItemId": "WK-1001",
"orderId": "ORD-1001",
"ticketId": "KT-1001",
"tableId": "T-08",
"station": "hot-line",
"state": "Queued",
"priority": 3,
"claimedBy": null,
"etaMinutes": 12
}
]
}
],
"availableStations": [ "hot-line", "grill", "pickup" ]
}
""";
}