using Bunit; using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances; namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Shared; /// /// bUnit tests for the combobox: the closed field, the /// panel that opens with every area collapsed, area expansion, instance selection /// (callback + close + field text), the disabled guard, the outside-click backdrop, /// parent-driven selection changes and the ItemLabel hook. /// public class InstancePickerTests : BunitContext { public InstancePickerTests() { JSInterop.Mode = JSRuntimeMode.Loose; } private static List Areas() => [ new("Line1") { Id = 1, SiteId = 1 }, new("Cell A") { Id = 2, SiteId = 1, ParentAreaId = 1 }, ]; private static List Instances() => [ new("P1") { Id = 7, SiteId = 1, AreaId = 2 }, new("Zulu") { Id = 8, SiteId = 1 }, ]; private IRenderedComponent RenderPicker( Action? onChanged = null, bool disabled = false, Func? itemLabel = null, int selectedInstanceId = 0) => Render(ps => { ps.Add(p => p.Areas, Areas()); ps.Add(p => p.Instances, Instances()); ps.Add(p => p.DataTestPrefix, "t"); ps.Add(p => p.Disabled, disabled); ps.Add(p => p.SelectedInstanceId, selectedInstanceId); if (itemLabel is not null) ps.Add(p => p.ItemLabel, itemLabel); if (onChanged is not null) ps.Add(p => p.SelectedInstanceIdChanged, onChanged); }); private static void Open(IRenderedComponent cut) => cut.Find("[data-test='t-toggle']").Click(); private static void ClickRow(IRenderedComponent cut, string text) => cut.FindAll("[data-test='t-row']").First(r => r.TextContent.Trim() == text).Click(); private static string InputValue(IRenderedComponent cut) => cut.Find("[data-test='t-input']").GetAttribute("value") ?? string.Empty; [Fact] public void Closed_ShowsNothingButTheField() { var cut = RenderPicker(); Assert.Empty(cut.FindAll("[data-test='t-panel']")); var input = cut.Find("[data-test='t-input']"); Assert.Equal("combobox", input.GetAttribute("role")); Assert.Equal("false", input.GetAttribute("aria-expanded")); } [Fact] public void Toggle_OpensPanel_WithAreasCollapsed() { var cut = RenderPicker(); Open(cut); Assert.Single(cut.FindAll("[data-test='t-panel']")); Assert.Equal("true", cut.Find("[data-test='t-input']").GetAttribute("aria-expanded")); var rows = cut.FindAll("[data-test='t-row']").Select(r => r.TextContent.Trim()).ToArray(); Assert.Equal(new[] { "Line1", "Zulu" }, rows); // P1 sits under a collapsed area, so its row is not rendered at all. Assert.Empty(cut.FindAll("[data-instance-id='7']")); // Area rows must not carry a data-instance-id at all (Blazor drops a null attribute). var areaRow = cut.FindAll("[data-test='t-row']").First(r => r.TextContent.Trim() == "Line1"); Assert.False(areaRow.HasAttribute("data-instance-id")); } [Fact] public void ClickingAnAreaLabel_ExpandsIt() { var cut = RenderPicker(); Open(cut); ClickRow(cut, "Line1"); Assert.Contains(cut.FindAll("[data-test='t-row']"), r => r.TextContent.Trim() == "Cell A"); Assert.Empty(cut.FindAll("[data-instance-id='7']")); ClickRow(cut, "Cell A"); Assert.Single(cut.FindAll("[data-instance-id='7']")); } [Fact] public void ClickingAnInstance_Selects_Closes_AndRaisesTheCallback() { int? picked = null; var cut = RenderPicker(onChanged: id => picked = id); Open(cut); ClickRow(cut, "Line1"); ClickRow(cut, "Cell A"); cut.Find("[data-instance-id='7']").Click(); Assert.Equal(7, picked); Assert.Empty(cut.FindAll("[data-test='t-panel']")); Assert.Equal("P1", InputValue(cut)); } [Fact] public void Disabled_NeverOpens() { var cut = RenderPicker(disabled: true); Assert.True(cut.Find("[data-test='t-input']").HasAttribute("disabled")); Assert.True(cut.Find("[data-test='t-toggle']").HasAttribute("disabled")); Open(cut); Assert.Empty(cut.FindAll("[data-test='t-panel']")); } [Fact] public void Backdrop_ClickClosesThePanel_WithoutChangingSelection() { int? picked = null; var cut = RenderPicker(onChanged: id => picked = id); Open(cut); cut.Find("[data-test='t-backdrop']").Click(); Assert.Empty(cut.FindAll("[data-test='t-panel']")); Assert.Null(picked); Assert.Equal(string.Empty, InputValue(cut)); } [Fact] public void ParentDrivenSelection_UpdatesTheFieldText() { var cut = RenderPicker(); cut.Render(ps => ps.Add(p => p.SelectedInstanceId, 8)); Assert.Equal("Zulu", InputValue(cut)); cut.Render(ps => ps.Add(p => p.SelectedInstanceId, 0)); Assert.Equal(string.Empty, InputValue(cut)); } [Fact] public void SiteChange_NewInstancesList_ClearsAStaleSelectionText() { var cut = RenderPicker(selectedInstanceId: 8); Assert.Equal("Zulu", InputValue(cut)); Open(cut); // A different site: neither the areas nor the previously selected instance survive. cut.Render(ps => { ps.Add(p => p.Areas, new List()); ps.Add(p => p.Instances, new List { new("Other") { Id = 99, SiteId = 2 } }); }); Assert.Equal(string.Empty, InputValue(cut)); Assert.Empty(cut.FindAll("[data-test='t-panel']")); } [Fact] public void ItemLabel_IsUsedForRowsAndField() { var cut = RenderPicker(itemLabel: i => i.UniqueName + " (x)"); Open(cut); var rows = cut.FindAll("[data-test='t-row']").Select(r => r.TextContent.Trim()).ToArray(); Assert.Equal(new[] { "Line1", "Zulu (x)" }, rows); ClickRow(cut, "Line1"); ClickRow(cut, "Cell A"); cut.Find("[data-instance-id='7']").Click(); Assert.Equal("P1 (x)", InputValue(cut)); } }