Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/HostsPanelWiringTests.cs
T
Joseph Doherty 34d60c4125 ui(hosts): declutter — per-cluster panels, stacked driver identity, abbreviated Last error, Controls in a dialog
The page ran members, the driver-instances heading, and every cluster group
together inside one panel; driver name and id slammed inline; one long driver
exception blew the table out sideways (Controls scrolled out of reach); and the
inline #546 expander row dumped a full-width panel into the table.

- One panel per cluster group, node chips in the panel head.
- Driver id renders on its own muted mono line under the name.
- Last error abbreviated to 60 chars (DisplayText.Abbreviate — #504 rule),
  full text on the tooltip and in the Controls dialog.
- DriverStatusPanel moved from an inline expander row to a modal (one at a
  time); the dialog re-resolves its row from the current groups each render so
  the 5 s rebuild can't strand it, and the Enabled-in-key recycle discipline
  carries over unchanged. HostsPanelWiringTests re-pinned to the dialog markup.

Live-verified on docker-dev: separated cards, in-viewport table, dialog opens
with live breaker/status data and grouped Reconnect|Restart, closes cleanly.
2026-08-10 17:34:37 -04:00

63 lines
2.9 KiB
C#

using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;
/// <summary>
/// Pins <c>DriverStatusPanel</c> to the <c>/hosts</c> page (Gitea #546). The panel is the only
/// component carrying the Restart/Reconnect driver controls, and it had ZERO references
/// repo-wide — the commands worked end to end over the mesh transport while no user could reach
/// them, and nothing failed to build, test or deploy. Deleting the last <c>&lt;DriverStatusPanel</c>
/// tag would silently restore exactly that state, so it is pinned here.
/// </summary>
/// <remarks>
/// This is a source scan rather than a rendering assertion because the repo has no bUnit (same
/// technique as <c>MeshRegistrationRoleScopingTests</c>; panel markup is otherwise live-verified).
/// A scan proves reachability of the component, not that it renders correctly.
/// </remarks>
[Trait("Category", "Unit")]
public sealed class HostsPanelWiringTests
{
private static string ReadHostsPageSource()
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx")))
dir = dir.Parent;
dir.ShouldNotBeNull("could not locate the repository root (no ZB.MOM.WW.OtOpcUa.slnx above the test binary)");
return File.ReadAllText(Path.Combine(
dir!.FullName, "src", "Server", "ZB.MOM.WW.OtOpcUa.AdminUI",
"Components", "Pages", "Hosts.razor"));
}
/// <summary>THE #546 regression pin: the panel must remain reachable from a routable page.</summary>
[Fact]
public void Hosts_page_renders_the_driver_status_panel()
{
ReadHostsPageSource().ShouldContain(
"<DriverStatusPanel",
Case.Sensitive,
customMessage:
"/hosts no longer renders DriverStatusPanel — the Restart/Reconnect driver controls " +
"are orphaned again with no reachable UI, which is Gitea #546");
}
/// <summary>
/// The panel must be fed the dialog driver's real identity and enabled-state, not literals.
/// Hard-coding any of the three would make every dialog drive the same driver, or claim a
/// disabled instance is live — both of which a source scan for the tag alone would pass.
/// Since the Controls dialog rework the panel renders once, inside the modal, bound to the
/// row that <c>FindControlsDriver()</c> re-resolves from the current groups (<c>cd</c>/<c>cg</c>)
/// — never to a cached row record, which the 5 s rebuild replaces.
/// </summary>
[Fact]
public void The_panel_is_bound_to_the_dialogs_own_driver_cluster_and_enabled_state()
{
var source = ReadHostsPageSource();
source.ShouldContain("DriverInstanceId=\"@cd.DriverInstanceId\"");
source.ShouldContain("ClusterId=\"@cg.ClusterId\"");
source.ShouldContain("Enabled=\"@cd.Enabled\"");
}
}