Skip to content

Commit 11a3203

Browse files
authored
Merge pull request CactuseSecurity#2762 from Y4nnikH/feat/test-ui-rsb
test(ui rsb): bUnit tests for link to rsb functionality
2 parents 722abe9 + 5e61348 commit 11a3203

File tree

5 files changed

+228
-2
lines changed

5 files changed

+228
-2
lines changed

roles/tests-unit/files/FWO.Test/FWO.Test.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
@@ -8,6 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11+
<PackageReference Include="bunit" Version="1.37.7" />
1112
<PackageReference Include="PuppeteerSharp" Version="20.0.5" />
1213
<PackageReference Include="NUnit" Version="4.3.2" />
1314
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
2+
3+
using FWO.Api.Client;
4+
using FWO.Api.Data;
5+
using FWO.Config.Api;
6+
using FWO.Report;
7+
using FWO.Report.Filter;
8+
9+
namespace FWO.Test
10+
{
11+
internal class SimulatedReport : ReportBase
12+
{
13+
public static SimulatedReport DetailedReport(ReportType reportType = ReportType.Rules) => new(new DynGraphqlQuery(""), new SimulatedUserConfig(), reportType)
14+
{
15+
ReportData = new()
16+
{
17+
ManagementData =
18+
[
19+
new ManagementReport
20+
{
21+
Id = 1,
22+
Name = "Management 1",
23+
Devices =
24+
[
25+
new DeviceReport
26+
{
27+
Id = 1,
28+
Name = "Device 1",
29+
Rules =
30+
[
31+
new() { Id = 1, Name = "Rule 1", MgmtId = 1 }
32+
]
33+
}
34+
],
35+
Objects =
36+
[
37+
new() { Id = 1, Name = "Object 1" },
38+
new() { Id = 2, Name = "Object 2" }
39+
],
40+
Services =
41+
[
42+
new() { Id = 1, Name = "Service 1" },
43+
new() { Id = 2, Name = "Service 2" }
44+
],
45+
Users =
46+
[
47+
new() { Id = 1, Name = "User 1" },
48+
new() { Id = 2, Name = "User 2" }
49+
],
50+
ReportObjects =
51+
[
52+
new() { Id = 1, Name = "Report Object 1" },
53+
new() { Id = 2, Name = "Report Object 2" }
54+
],
55+
ReportServices =
56+
[
57+
new() { Id = 1, Name = "Report Service 1" },
58+
new() { Id = 2, Name = "Report Service 2" }
59+
],
60+
ReportUsers =
61+
[
62+
new() { Id = 1, Name = "Report User 1" },
63+
new() { Id = 2, Name = "Report User 2" }
64+
]
65+
}
66+
]
67+
}
68+
};
69+
70+
public SimulatedReport(DynGraphqlQuery query, UserConfig userConfig, ReportType reportType) : base(query, userConfig, reportType)
71+
{
72+
}
73+
74+
override public Task<bool> GetObjectsForManagementInReport(Dictionary<string, object> objQueryVariables, ObjCategory objects, int maxFetchCycles, ApiConnection apiConnection, Func<ReportData, Task> callback)
75+
{
76+
callback(DetailedReport().ReportData);
77+
return Task.FromResult(true);
78+
}
79+
80+
override public Task Generate(int rulesPerFetch, ApiConnection apiConnection, Func<ReportData, Task> callback, CancellationToken ct)
81+
{
82+
return Task.CompletedTask;
83+
}
84+
85+
override public Task<bool> GetObjectsInReport(int objectsPerFetch, ApiConnection apiConnection, Func<ReportData, Task> callback)
86+
{
87+
return Task.FromResult(true);
88+
}
89+
90+
override public string ExportToCsv()
91+
{
92+
return "";
93+
}
94+
95+
override public string ExportToJson()
96+
{
97+
return "";
98+
}
99+
100+
override public string ExportToHtml()
101+
{
102+
return "";
103+
}
104+
105+
override public string SetDescription()
106+
{
107+
return "";
108+
}
109+
}
110+
}

roles/tests-unit/files/FWO.Test/SimulatedUserConfig.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,15 @@ internal class SimulatedUserConfig : UserConfig
8282
{"add_members",": Add Members"},
8383
{"remove_members",": Remove Members"},
8484
{"new_app_zone", "New AppZone: " },
85-
{"update_app_zone", "Update AppZone: " }
85+
{"update_app_zone", "Update AppZone: " },
86+
{"objects","Objects"},
87+
{"all","All"},
88+
{"report","Report"},
89+
{"rule", "Rule"},
90+
{"collapse_all","Collapse All"},
91+
{"clear_all", "Clear All"},
92+
{"used_objects", "Used Objects"},
93+
{"object_fetch", "Object Fetch"},
8694
};
8795

8896
public override string GetText(string key)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
using Bunit;
3+
using Bunit.TestDoubles;
4+
using NUnit.Framework;
5+
using FWO.Api.Client;
6+
using FWO.Config.Api;
7+
using FWO.Report;
8+
using FWO.Ui.Shared;
9+
using Microsoft.Extensions.DependencyInjection;
10+
using AngleSharp.Dom;
11+
using AngleSharp.Css.Dom;
12+
using System.Text.RegularExpressions;
13+
using FWO.Logging;
14+
15+
namespace FWO.Test
16+
{
17+
[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]
18+
public class UiRsbLinkTest : Bunit.TestContext
19+
{
20+
static readonly UserConfig userConfig = new SimulatedUserConfig
21+
{
22+
ModNamingConvention = "{\"networkAreaRequired\":true,\"fixedPartLength\":4,\"freePartLength\":5,\"networkAreaPattern\":\"NA\",\"appRolePattern\":\"AR\"}"
23+
};
24+
static readonly ApiConnection apiConnection = new UiRsbTestApiConn();
25+
static readonly ReportBase currentReport = SimulatedReport.DetailedReport();
26+
27+
[Test]
28+
public void ObjShouldBeVisibleAfterNavigation()
29+
{
30+
// Arrange
31+
Services.AddSingleton(userConfig);
32+
Services.AddSingleton(apiConnection);
33+
Services.AddLocalization();
34+
35+
var objToFind = currentReport.ReportData.ManagementData[0].Objects[1];
36+
var simObjHtml = ReportDevicesBase.ConstructLink(ObjCatString.NwObj, "", 0, objToFind.Id, objToFind.Name, OutputLocation.report, currentReport.ReportData.ManagementData[0].Id, "");
37+
var hrefValue = Regex.Match(simObjHtml, "href=\"([^\"]*)\"").Groups[1].Value;
38+
var link = $"https://localhost/{hrefValue}";
39+
40+
var navigationManager = Services.GetRequiredService<FakeNavigationManager>();
41+
navigationManager.NavigateTo(link);
42+
43+
// Mock JS interop
44+
JSInterop.Setup<string>("getCurrentUrl").SetResult(link);
45+
var scrollIntoRSBViewInvocation = JSInterop.Setup<bool>("scrollIntoRSBView", _ => true).SetResult(true);
46+
var removeUrlFragmentInvocation = JSInterop.SetupVoid("removeUrlFragment");
47+
48+
// Act
49+
var cut = RenderComponent<RightSidebar>(parameters => parameters
50+
.Add(p => p.CurrentReport, currentReport)
51+
.Add(p => p.SelectedRules, [currentReport.ReportData.ManagementData[0].Devices[0].Rules![0]]));
52+
53+
// Assert
54+
Assert.That(scrollIntoRSBViewInvocation.Invocations, Is.Not.Empty, "scrollIntoRSBView should have been called");
55+
var invocation = scrollIntoRSBViewInvocation.Invocations.First();
56+
var parameter = invocation.Arguments[0];
57+
Assert.That(parameter, Is.Not.Null, "scrollIntoRSBView was called with a null parameter");
58+
Assert.That(parameter, Is.InstanceOf<string>(), "scrollIntoRSBView was called with a non-string parameter");
59+
Assert.That((string)parameter!, Is.Not.Empty, "scrollIntoRSBView was called with an empty string");
60+
61+
var element = cut.Find($"#{parameter}");
62+
Assert.That(element, Is.Not.Null, "Element with id {parameter} not found in right sidebar");
63+
Assert.That(IsElementVisible(element), Is.True, "Element is not visible (might be incorrect tab or uncollapsed)");
64+
}
65+
66+
private bool IsElementVisible(IElement? element)
67+
{
68+
while (element != null)
69+
{
70+
var display = element.GetStyle().GetPropertyValue("display");
71+
if (display == "none")
72+
{
73+
Log.WriteError("Test UI RSB", $"Element {element.TagName} is not visible");
74+
return false;
75+
}
76+
element = element.ParentElement;
77+
}
78+
return true;
79+
}
80+
}
81+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
using FWO.Api.Client.Queries;
3+
using GraphQL;
4+
using FWO.Api.Data;
5+
using FWO.Report;
6+
7+
namespace FWO.Test
8+
{
9+
internal class UiRsbTestApiConn : SimulatedApiConnection
10+
{
11+
public override async Task<QueryResponseType> SendQueryAsync<QueryResponseType>(string query, object? variables = null, string? operationName = null)
12+
{
13+
Type responseType = typeof(QueryResponseType);
14+
if(responseType == typeof(List<ManagementReport>))
15+
{
16+
List<ManagementReport> reports = SimulatedReport.DetailedReport().ReportData.ManagementData;
17+
GraphQLResponse<dynamic> response = new(){ Data = reports };
18+
return response.Data;
19+
}
20+
else
21+
{
22+
throw new NotImplementedException();
23+
}
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)