25a1e61141
The shared RawConfirmDialog sat inside the Alarms tab branch, so Remove reference (Tags) and Delete virtual tag (Virtual Tags) set it visible on a page that did not render it. Pinned by brace depth in DeleteConfirmationWiringTests.
66 lines
3.1 KiB
C#
66 lines
3.1 KiB
C#
using System.Text.RegularExpressions;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
|
|
|
|
/// <summary>
|
|
/// R04 H1 source pin (no bUnit): every destructive button on the equipment page and the script editor
|
|
/// opens a confirm dialog instead of deleting on the first click. The live check (each delete confirms)
|
|
/// is in the Wave 4 docker-dev pass.
|
|
/// </summary>
|
|
[Trait("Category", "Unit")]
|
|
public sealed class DeleteConfirmationWiringTests
|
|
{
|
|
[Fact]
|
|
public void Equipment_page_routes_every_destructive_row_action_through_the_confirm()
|
|
{
|
|
var src = AdminUiSource.Read("Components", "Pages", "Uns", "EquipmentPage.razor");
|
|
|
|
src.ShouldContain("<RawConfirmDialog @bind-Visible=\"_confirmVisible\"");
|
|
src.ShouldContain("@onclick=\"() => ConfirmRemoveReference(r)\"");
|
|
src.ShouldContain("@onclick=\"() => ConfirmDeleteVirtualTag(v.VirtualTagId, v.Name)\"");
|
|
src.ShouldContain("@onclick=\"() => ConfirmDeleteAlarm(a.ScriptedAlarmId, a.Name)\"");
|
|
|
|
// No danger button may call a delete handler directly.
|
|
Regex.Matches(src, @"btn-outline-danger[^>]*@onclick=""\(\) => (Delete|Remove)\w*\(").Count.ShouldBe(0);
|
|
// Positive control: the page still has its three danger buttons.
|
|
Regex.Matches(src, "btn-outline-danger").Count.ShouldBe(3);
|
|
}
|
|
|
|
/// <summary>
|
|
/// #832: the shared confirm used to sit INSIDE the Alarms tab branch, so it was on the page only while that
|
|
/// tab was showing — the Tags tab's Remove and the Virtual Tags tab's Delete set the dialog visible and
|
|
/// nothing appeared. Pinned by brace depth: the dialog must be at the depth of the tab <c>@if</c> chain,
|
|
/// not inside any branch of it.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Equipment_page_confirm_renders_outside_every_tab_branch()
|
|
{
|
|
var src = AdminUiSource.Read("Components", "Pages", "Uns", "EquipmentPage.razor");
|
|
var markup = src[..src.IndexOf("@code", StringComparison.Ordinal)];
|
|
|
|
int DepthAt(int index) =>
|
|
markup[..index].Count(c => c == '{') - markup[..index].Count(c => c == '}');
|
|
|
|
var tabChain = markup.IndexOf("@if (_activeTab == \"details\")", StringComparison.Ordinal);
|
|
var dialog = markup.IndexOf("<RawConfirmDialog", StringComparison.Ordinal);
|
|
tabChain.ShouldBeGreaterThan(0);
|
|
dialog.ShouldBeGreaterThan(tabChain, "the confirm follows the tab chain");
|
|
DepthAt(dialog).ShouldBe(DepthAt(tabChain), "the confirm must not be nested inside a tab branch");
|
|
|
|
// Positive control: a tab-scoped modal really is one level deeper, so the depth probe can tell them apart.
|
|
DepthAt(markup.IndexOf("<ScriptedAlarmModal", StringComparison.Ordinal)).ShouldBe(DepthAt(tabChain) + 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void Script_editor_delete_confirms()
|
|
{
|
|
var src = AdminUiSource.Read("Components", "Pages", "ScriptEdit.razor");
|
|
|
|
src.ShouldContain("@onclick=\"() => _confirmDeleteVisible = true\"");
|
|
src.ShouldContain("OnConfirm=\"DeleteAsync\"");
|
|
src.ShouldNotContain("@onclick=\"DeleteAsync\"");
|
|
}
|
|
}
|