using System.Security.Claims; using Bunit; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.DependencyInjection; using ScadaLink.Security; using AuditLogPage = ScadaLink.CentralUI.Components.Pages.Audit.AuditLogPage; using NavMenu = ScadaLink.CentralUI.Components.Layout.NavMenu; namespace ScadaLink.CentralUI.Tests.Pages; /// /// Scaffold tests for the new Audit Log page (#23 M7-T1) and the Audit /// nav group that hosts both it and the renamed Configuration Audit Log /// (#23 M7 Bundle A). /// /// These are render-only smoke tests — the filter bar and results grid /// are intentional placeholders that Bundle B fills in. The tests pin /// the page route, page heading, nav group label, and the two child /// links so later bundles cannot regress the scaffolding. /// public class AuditLogPageScaffoldTests : BunitContext { private static ClaimsPrincipal BuildPrincipal(params string[] roles) { var claims = new List { new("Username", "tester") }; claims.AddRange(roles.Select(r => new Claim(JwtTokenService.RoleClaimType, r))); return new ClaimsPrincipal(new ClaimsIdentity(claims, "TestAuth")); } private IRenderedComponent RenderAuditLogPage(params string[] roles) { var user = BuildPrincipal(roles); Services.AddSingleton(new TestAuthStateProvider(user)); Services.AddAuthorizationCore(); AuthorizationPolicies.AddScadaLinkAuthorization(Services); Services.AddSingleton(); return Render(); } private IRenderedComponent RenderNavMenu(params string[] roles) { var user = BuildPrincipal(roles); Services.AddSingleton(new TestAuthStateProvider(user)); Services.AddAuthorizationCore(); AuthorizationPolicies.AddScadaLinkAuthorization(Services); Services.AddSingleton(); var host = Render(parameters => parameters .Add(p => p.ChildContent, (RenderFragment)(builder => { builder.OpenComponent(0); builder.CloseComponent(); }))); return host.FindComponent(); } [Fact] public void AuditLogPage_Renders_PageHeading() { var cut = RenderAuditLogPage("Admin"); cut.WaitForAssertion(() => { // The H1 is the only positive scaffold assertion — the filter // bar and grid are still placeholders the Bundle B work fills. Assert.Contains(" { Assert.Contains(">Audit<", cut.Markup); Assert.Contains("/audit/log", cut.Markup); }); } [Fact] public void NavMenu_Contains_ConfigurationAuditLog_Link_UnderAuditGroup() { var cut = RenderNavMenu("Admin", "Design", "Deployment"); cut.WaitForAssertion(() => { // Both audit pages must appear after the Audit section header // in the rendered nav. We check both links + that the header // comes before either link in the markup, so they are in the // Audit group rather than orphaned under Monitoring. Assert.Contains("/audit/configuration", cut.Markup); Assert.Contains("/audit/log", cut.Markup); var headerIdx = cut.Markup.IndexOf(">Audit<", StringComparison.Ordinal); var configIdx = cut.Markup.IndexOf("/audit/configuration", StringComparison.Ordinal); var logIdx = cut.Markup.IndexOf("/audit/log", StringComparison.Ordinal); Assert.True(headerIdx >= 0 && headerIdx < configIdx, "Audit section header must precede the Configuration Audit Log link."); Assert.True(headerIdx >= 0 && headerIdx < logIdx, "Audit section header must precede the Audit Log link."); }); } }