diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs
index 16db7dbe..bbe1892b 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunner.Helpers.cs
@@ -100,6 +100,34 @@ public static partial class CliRunner
await RunAsync([.. args]);
}
+ ///
+ /// Adds an alarm to a template via template alarm add (using the typed setpoint
+ /// flags) and returns its new id. Throws on failure.
+ ///
+ public static async Task AddAlarmAsync(
+ int templateId, string name, string triggerType = "HiLo", int priority = 500,
+ string? attribute = null, double? hi = null, double? hiHi = null,
+ double? lo = null, double? loLo = null)
+ {
+ var inv = System.Globalization.CultureInfo.InvariantCulture;
+ var args = new List
+ {
+ "template", "alarm", "add",
+ "--template-id", templateId.ToString(inv),
+ "--name", name,
+ "--trigger-type", triggerType,
+ "--priority", priority.ToString(inv),
+ };
+ if (attribute is not null) { args.Add("--attribute"); args.Add(attribute); }
+ if (hi.HasValue) { args.Add("--hi"); args.Add(hi.Value.ToString(inv)); }
+ if (hiHi.HasValue) { args.Add("--hihi"); args.Add(hiHi.Value.ToString(inv)); }
+ if (lo.HasValue) { args.Add("--lo"); args.Add(lo.Value.ToString(inv)); }
+ if (loLo.HasValue) { args.Add("--lolo"); args.Add(loLo.Value.ToString(inv)); }
+
+ using var doc = await RunJsonAsync([.. args]);
+ return RequireId(doc, "template alarm add");
+ }
+
///
/// Creates an area under a site via site area create and returns its
/// new id.
@@ -558,6 +586,18 @@ public static partial class CliRunner
}
}
+ /// Best-effort delete of an instance alarm override (teardown). Never throws.
+ public static async Task DeleteInstanceAlarmOverrideAsync(int instanceId, string alarmCanonicalName)
+ {
+ var inv = System.Globalization.CultureInfo.InvariantCulture;
+ try
+ {
+ await RunAsync("instance", "alarm-override", "delete",
+ "--instance-id", instanceId.ToString(inv), "--alarm", alarmCanonicalName);
+ }
+ catch { /* best-effort teardown — never mask the test's own failure. */ }
+ }
+
///
/// Exports a Transport bundle scoped to a single template via
/// bundle export.
diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs
index 76793453..0fe2c7b6 100644
--- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs
+++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/Cluster/CliRunnerHelpersTests.cs
@@ -188,4 +188,23 @@ public class CliRunnerHelpersTests
}
finally { await CliRunner.DeleteRoleMappingAsync(id); }
}
+
+ ///
+ /// Exercises the typed HiLo setpoint flags end-to-end: a template alarm added via
+ /// with --hi/--hihi returns a
+ /// positive id, confirming the server accepted the serialized trigger-config JSON.
+ ///
+ [SkippableFact]
+ public async Task AddAlarmWithTypedFlags_RoundTrips()
+ {
+ Skip.IfNot(await ClusterAvailability.IsAvailableAsync(), ClusterAvailability.SkipReason);
+ var id = await CliRunner.CreateTemplateAsync(CliRunner.UniqueName("tmpl"));
+ try
+ {
+ await CliRunner.AddAttributeAsync(id, "Value", "Double");
+ var alarmId = await CliRunner.AddAlarmAsync(id, "HiHi", "HiLo", 500, attribute: "Value", hi: 80, hiHi: 95);
+ Assert.True(alarmId > 0); // server accepted the serialized trigger-config JSON
+ }
+ finally { await CliRunner.DeleteTemplateAsync(id); }
+ }
}