namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
///
/// Task 24: the template editor exposes a Native Alarm Sources subsection (a new
/// tab) for authoring read-only native alarm bindings. TemplateEdit is a
/// heavyweight page (~10 injected services with their own graphs); like the other
/// TemplateEdit coverage in this suite (see TestRunWarningTests), these are
/// structural assertions over the component source that pin the subsection's
/// wiring — the tab, the authoring form (connection dropdown, source reference,
/// filter, lock), and the repository-direct CRUD calls — so it cannot silently
/// regress. The CRUD behaviour itself is covered end-to-end by the ManagementActor
/// native-alarm-source handler tests.
///
public class TemplateNativeAlarmSourceEditorTests
{
private static string DesignComponentsRoot
{
get
{
var dir = AppContext.BaseDirectory;
for (var i = 0; i < 6 && dir is not null; i++)
dir = Directory.GetParent(dir)?.FullName;
return Path.Combine(dir!, "src", "ZB.MOM.WW.ScadaBridge.CentralUI",
"Components", "Pages", "Design");
}
}
private static string TemplateEditMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateEdit.razor"));
// M10 residual: the authoring form moved out of the page into the dialog body
// component hosted by IDialogService.ShowAsync. The field-level assertions
// below follow it there; the tab, the connection filtering, and the CRUD
// wiring all still live on the page.
private static string NativeSourceDialogMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateNativeAlarmSourceDialog.razor"));
[Fact]
public void TemplateEditor_HasNativeAlarmsTab()
{
var markup = TemplateEditMarkup;
Assert.Contains("_activeTab = \"native-alarms\"", markup);
Assert.Contains("Native Alarms", markup);
Assert.Contains("RenderNativeAlarmsTab", markup);
Assert.Contains("Native Alarm Sources", markup);
}
[Fact]
public void NativeAlarmsForm_HasConnectionSourceFilterAndLockFields()
{
var pageMarkup = TemplateEditMarkup;
// Connection dropdown filtered to alarm-capable protocols via the
// single-source-of-truth Commons helper. The OpcUa/MxGateway literal set
// now lives in AlarmCapableProtocols (Commons) — pinned by
// AlarmCapableProtocolsTests — so this page only needs to delegate to it.
Assert.Contains("_alarmCapableConnections", pageMarkup);
Assert.Contains("AlarmCapableProtocols.IsAlarmCapable", pageMarkup);
// …and hands the filtered list to the dialog body.
Assert.Contains("AlarmCapableConnections=", pageMarkup);
// The authoring form fields now live in the dialog body component.
var dialogMarkup = NativeSourceDialogMarkup;
Assert.Contains("@bind=\"_nasName\"", dialogMarkup);
Assert.Contains("@bind=\"_nasConnection\"", dialogMarkup);
Assert.Contains("@bind=\"_nasSourceRef\"", dialogMarkup);
Assert.Contains("@bind=\"_nasFilter\"", dialogMarkup);
Assert.Contains("@bind=\"_nasIsLocked\"", dialogMarkup);
}
[Fact]
public void NativeAlarmsForm_IsHostedByTheDialogService()
{
// M10 residual: the page-embedded modal is gone — the form opens through
// IDialogService.ShowAsync so the host owns the backdrop, focus trap,
// Escape, and focus restoration.
var pageMarkup = TemplateEditMarkup;
Assert.Contains(" Context", dialogMarkup);
}
[Fact]
public void NativeAlarmsCrud_WiresRepositoryAddUpdateDeleteWithSave()
{
var markup = TemplateEditMarkup;
Assert.Contains("AddTemplateNativeAlarmSourceAsync", markup);
Assert.Contains("UpdateTemplateNativeAlarmSourceAsync", markup);
Assert.Contains("DeleteTemplateNativeAlarmSourceAsync", markup);
Assert.Contains("GetNativeAlarmSourcesByTemplateIdAsync", markup);
Assert.Contains("SaveChangesAsync", markup);
// Add/edit/delete handlers are wired to the UI.
Assert.Contains("OpenAddNativeSourceDialog", markup);
Assert.Contains("OpenEditNativeSourceDialog", markup);
Assert.Contains("SaveNativeSourceDraftAsync", markup);
Assert.Contains("DeleteNativeSource", markup);
}
}