102 lines
4.3 KiB
C#
102 lines
4.3 KiB
C#
using Bunit;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using NSubstitute;
|
|
using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Dialogs;
|
|
using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components;
|
|
|
|
public class NodeBrowserDialogSelectionTests : BunitContext
|
|
{
|
|
private readonly IBrowseService _browse = Substitute.For<IBrowseService>();
|
|
|
|
public NodeBrowserDialogSelectionTests()
|
|
{
|
|
Services.AddSingleton(_browse);
|
|
_browse.BrowseChildrenAsync(
|
|
Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string?>(),
|
|
Arg.Any<string?>(), Arg.Any<CancellationToken>())
|
|
.Returns(new BrowseNodeResult(Array.Empty<BrowseNode>(), Truncated: false, Failure: null));
|
|
_browse.SearchAsync(
|
|
Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(),
|
|
Arg.Any<int>(), Arg.Any<int>(), Arg.Any<CancellationToken>())
|
|
.Returns(new SearchAddressSpaceResult(
|
|
Matches: new[]
|
|
{
|
|
new AddressSpaceMatch(
|
|
new BrowseNode("ns=2;s=Pump1.Speed", "Speed", BrowseNodeClass.Variable, HasChildren: false, DataType: "Double"),
|
|
Path: "Devices/Pump1/Speed"),
|
|
},
|
|
CapReached: false, Failure: null));
|
|
}
|
|
|
|
[Fact]
|
|
public void Confirm_emits_full_node_with_datatype_on_OnNodeSelected()
|
|
{
|
|
BrowseNode? captured = null;
|
|
var cut = Render<NodeBrowserDialog>(p => p
|
|
.Add(c => c.SiteId, "plant-a")
|
|
.Add(c => c.ConnectionName, "PLC-OPC")
|
|
.Add(c => c.OnNodeSelected, EventCallback.Factory.Create<BrowseNode>(this, n => captured = n)));
|
|
cut.InvokeAsync(() => cut.Instance.ShowAsync("plant-a", "PLC-OPC", null));
|
|
cut.Render();
|
|
|
|
cut.Find("[data-test=node-search-input]").Input("Pump1");
|
|
cut.Find("[data-test=node-search-button]").Click();
|
|
cut.FindAll("[data-test=node-search-result] a")[0].Click();
|
|
cut.Find(".modal-footer .btn-primary").Click();
|
|
|
|
Assert.NotNull(captured);
|
|
Assert.Equal("ns=2;s=Pump1.Speed", captured!.NodeId);
|
|
Assert.Equal("Double", captured.DataType);
|
|
}
|
|
|
|
[Fact]
|
|
public void ShowSearch_false_hides_search_box()
|
|
{
|
|
var cut = Render<NodeBrowserDialog>(p => p
|
|
.Add(c => c.SiteId, "plant-a")
|
|
.Add(c => c.ConnectionName, "PLC-MX")
|
|
.Add(c => c.ShowSearch, false));
|
|
cut.InvokeAsync(() => cut.Instance.ShowAsync("plant-a", "PLC-MX", null));
|
|
cut.Render();
|
|
|
|
Assert.Empty(cut.FindAll("[data-test=node-search-input]"));
|
|
}
|
|
|
|
// The Secured Writes page browses MxGateway with ShowSearch=false, so the
|
|
// ONLY user-reachable selection path in production is the tree (Select(TreeNode)
|
|
// → _selectedNode = node.Source). This guards that path end-to-end: a tree-node
|
|
// click must carry the node's DataType through Confirm → OnNodeSelected.
|
|
[Fact]
|
|
public void TreeSelect_emits_full_node_with_datatype_on_OnNodeSelected()
|
|
{
|
|
_browse.BrowseChildrenAsync(
|
|
Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string?>(),
|
|
Arg.Any<string?>(), Arg.Any<CancellationToken>())
|
|
.Returns(new BrowseNodeResult(
|
|
new[] { new BrowseNode("Area1.Pump.Speed", "Speed", BrowseNodeClass.Variable, HasChildren: false, DataType: "Float") },
|
|
Truncated: false, Failure: null));
|
|
|
|
BrowseNode? captured = null;
|
|
var cut = Render<NodeBrowserDialog>(p => p
|
|
.Add(c => c.SiteId, "plant-a")
|
|
.Add(c => c.ConnectionName, "PLC-MX")
|
|
.Add(c => c.ShowSearch, false)
|
|
.Add(c => c.OnNodeSelected, EventCallback.Factory.Create<BrowseNode>(this, n => captured = n)));
|
|
cut.InvokeAsync(() => cut.Instance.ShowAsync("plant-a", "PLC-MX", null));
|
|
cut.Render();
|
|
|
|
// Click the tree node's select link (tree path, not search).
|
|
cut.Find(".node-browser-tree a").Click();
|
|
cut.Find(".modal-footer .btn-primary").Click();
|
|
|
|
Assert.NotNull(captured);
|
|
Assert.Equal("Area1.Pump.Speed", captured!.NodeId);
|
|
Assert.Equal("Float", captured.DataType);
|
|
}
|
|
}
|