using Bunit; using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Deployment; using ZB.MOM.WW.ScadaBridge.Commons.Types.Debugging; namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Deployment; /// /// Flow Debugger outbound-calls plan (2026-09-06) Task 8: the step detail panel's Lifecycle tab, /// outbound "Where this ran" fields and kind-specific Input tab labels. /// public class FlowStepDetailTests : BunitContext { private static readonly DateTimeOffset T0 = new(2026, 9, 6, 12, 0, 0, TimeSpan.Zero); private static FlowStep Step(FlowStepKind kind, FlowStepOutcome outcome, string target, IReadOnlyList? lifecycle = null) => new(Guid.NewGuid(), Guid.NewGuid(), null, kind, FlowLane.External, target, "Delivered ยท cached", T0, 4100, outcome, "{\"id\":1}", "{\"ok\":true}", outcome == FlowStepOutcome.Failed ? "boom" : null, "site-a", "node-a", "M1", target, null, lifecycle); private static IReadOnlyList CachedLifecycle(string terminalStatus) => [ new(Guid.NewGuid(), "CachedSubmit", "Submitted", T0, "node-a", null, null), new(Guid.NewGuid(), "ApiCallCached", "Attempted", T0.AddSeconds(3), "node-a", "503 Service Unavailable", 40), new(Guid.NewGuid(), "CachedResolve", terminalStatus, T0.AddMilliseconds(4100), "node-b", null, null), ]; [Fact] public void LifecycleTab_RendersRowsInTimeOrder_AndDeliveredBy() { var step = Step(FlowStepKind.ApiCall, FlowStepOutcome.Ok, "Delmia.AckRecipe", CachedLifecycle("Delivered")); var cut = Render(p => p.Add(x => x.Step, step)); cut.Find("[data-test=flow-step-tab-lifecycle]").Click(); var rows = cut.FindAll("[data-test=flow-step-lifecycle] tbody tr"); Assert.Equal(3, rows.Count); Assert.Contains("CachedSubmit", rows[0].TextContent); Assert.Contains("Submitted", rows[0].TextContent); Assert.Contains("503 Service Unavailable", rows[1].TextContent); Assert.Contains("CachedResolve", rows[2].TextContent); Assert.Contains("node-b", rows[2].TextContent); Assert.Contains("12:00:04.100", rows[2].TextContent); var where = cut.Find("[data-test=flow-step-where]").TextContent; Assert.Contains("System", where); Assert.Contains("Delmia.AckRecipe", where); Assert.Contains("Delivered by", where); Assert.Contains("node-b", where); Assert.Empty(cut.FindAll("[data-test=flow-step-parked-hint]")); } [Fact] public void NoLifecycle_HidesTheTab() { var step = Step(FlowStepKind.AttributeWrite, FlowStepOutcome.Ok, "A") with { Lane = FlowLane.Tags }; var cut = Render(p => p.Add(x => x.Step, step)); Assert.Empty(cut.FindAll("[data-test=flow-step-tab-lifecycle]")); Assert.Equal("Input", cut.Find("[data-test=flow-step-tab-input]").TextContent.Trim()); } [Fact] public void ParkedNotify_ShowsHint_AndListLabel_AndParkedBadge() { var lifecycle = new List { new(Guid.NewGuid(), "NotifySend", "Submitted", T0, "node-a", null, null), new(Guid.NewGuid(), "NotifyDeliver", "Parked", T0.AddSeconds(9), "central-a", "retries exhausted", null), }; var step = Step(FlowStepKind.Notify, FlowStepOutcome.Parked, "Planners", lifecycle); var cut = Render(p => p.Add(x => x.Step, step)); Assert.Equal("Parked", cut.Find("[data-test=flow-step-outcome]").TextContent.Trim()); Assert.Contains("warning", cut.Find("[data-test=flow-step-outcome]").ClassName); Assert.Equal("Subject + body", cut.Find("[data-test=flow-step-tab-input]").TextContent.Trim()); var where = cut.Find("[data-test=flow-step-where]").TextContent; Assert.Contains("List", where); Assert.Contains("central-a", where); cut.Find("[data-test=flow-step-tab-lifecycle]").Click(); Assert.Contains("Site Calls / Notification", cut.Find("[data-test=flow-step-parked-hint]").TextContent); } [Theory] [InlineData(FlowStepKind.ApiCall, "Request", "System")] [InlineData(FlowStepKind.DbCall, "SQL + parameters", "Connection")] [InlineData(FlowStepKind.Notify, "Subject + body", "List")] public void OutboundKinds_LabelInputTabAndTarget(FlowStepKind kind, string inputLabel, string targetLabel) { var step = Step(kind, FlowStepOutcome.Pending, "T"); var cut = Render(p => p.Add(x => x.Step, step)); Assert.Equal(inputLabel, cut.Find("[data-test=flow-step-tab-input]").TextContent.Trim()); Assert.Contains(targetLabel, cut.Find("[data-test=flow-step-where]").TextContent); Assert.Equal("Pending", cut.Find("[data-test=flow-step-outcome]").TextContent.Trim()); } }