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));
}
}