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