using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Drivers; /// /// lmxopcua#847: a refused driver/device save stacked two copies of the same error box (the live gate box plus /// the gate text copied into the save error), and a resubmit left the previous refusal standing. /// [Trait("Category", "Unit")] public sealed class SaveRefusalNoticesTests { [Fact] public void Nothing_to_show_renders_nothing() => SaveRefusalNotices.Messages(null, " ").ShouldBeEmpty(); [Fact] public void The_same_refusal_from_gate_and_save_renders_once() => SaveRefusalNotices.Messages("Credential refused.", "Credential refused.").ShouldBe(["Credential refused."]); [Fact] public void A_save_error_that_wraps_the_gate_text_renders_once() => SaveRefusalNotices.Messages("Credential refused.", "Save failed: Credential refused.") .ShouldBe(["Credential refused."]); [Fact] public void Distinct_gate_and_server_errors_both_render_gate_first() => SaveRefusalNotices.Messages("Credential refused.", "Row was modified by someone else.") .ShouldBe(["Credential refused.", "Row was modified by someone else."]); [Fact] public void A_server_error_alone_renders() => SaveRefusalNotices.Messages(null, "Duplicate name.").ShouldBe(["Duplicate name."]); [Theory] [InlineData("DriverConfigModal.razor", "_driverConfigJson")] [InlineData("DeviceModal.razor", "_deviceConfigJson")] public void Both_modals_render_one_shared_error_area_and_reset_it_on_resubmit_and_edit(string file, string jsonField) { var src = AdminUiSource.Read("Components", "Shared", "Drivers", file); src.ShouldContain("@_saveError"); // The gate refusal is no longer COPIED into _saveError (the source of the duplicate box). src.ShouldNotContain($"_saveError = DriverConfigSaveGate.Validate(_driverType, {jsonField});"); src.ShouldContain("_saveError = null;\n if (DriverConfigSaveGate.Validate("); // An edit clears a stale server refusal. src.ShouldContain($"v => {{ {jsonField} = v; _saveError = null; }}"); } } /// /// lmxopcua#847: Test Connect / browse-open refusals were cut down inside an uppercase chip ("SEC…") with the /// real reason only in a hover tooltip. Every site now renders the shared RefusalChip, which prints the /// full message under a short chip. /// [Trait("Category", "Unit")] public sealed class RefusalChipWiringTests { [Theory] [InlineData("Drivers/DriverTestConnectButton.razor")] [InlineData("Raw/RawBrowseModal.razor")] [InlineData("Drivers/Pickers/AbCipAddressPickerBody.razor")] [InlineData("Drivers/Pickers/FOCASAddressPickerBody.razor")] [InlineData("Drivers/Pickers/GalaxyAddressPickerBody.razor")] [InlineData("Drivers/Pickers/OpcUaClientAddressPickerBody.razor")] [InlineData("Drivers/Pickers/SqlAddressPickerBody.razor")] [InlineData("Drivers/Pickers/TwinCATAddressPickerBody.razor")] public void Refusal_sites_render_the_full_message_via_RefusalChip(string relative) { var src = AdminUiSource.Read(["Components", "Shared", .. relative.Split('/')]); src.ShouldContain("@Message"); src.ShouldNotContain("Abbreviate"); } }