sqlinsight-pro/tests/SQLInsight.IntegrationTests/NavigationTests.cs
Søren Eggert Lundsteen Olsen cc71fb12c6 Menu in foldable groups
The web menu is grouped with details/summary (no script, CSP safe):
Overvågning, Analyse, Konfiguration og sikkerhed, Rapporter, Dynamics AX
(hidden until a database is recognised as AX), Support, System and
Community. The group holding the current page is open, including pages
under /instanser/{navn}/. Per-instance entries go through /vaelg/{side}
(straight to the instance when there is only one). On narrow screens
the whole menu folds behind a "Menu" checkbox toggle.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 09:17:43 +02:00

90 lines
4 KiB
C#

using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using SQLInsight.Core.Instances;
using SQLInsight.Repository;
namespace SQLInsight.IntegrationTests;
/// <summary>The menu in foldable groups, and the instance chooser behind per-instance menu entries.</summary>
[Collection(SqlServerTestGroup.Name)]
[Trait("Category", "Integration")]
public partial class NavigationTests(SqlServerFixture sql) : IAsyncLifetime
{
private readonly string _database = "SQLInsightNav_" + Guid.NewGuid().ToString("N")[..8];
private WebApplicationFactory<Program> _factory = null!;
private InsightRepository _repository = null!;
public async Task InitializeAsync()
{
await sql.ExecuteAsSaAsync($"CREATE DATABASE [{_database}];");
_repository = new InsightRepository(sql.DatabaseConnectionString(_database));
await _repository.MigrateAsync();
_factory = new WebApplicationFactory<Program>().WithWebHostBuilder(b =>
{
b.UseEnvironment("Development");
b.UseSetting("SQLInsight:Repository:ConnectionString", sql.DatabaseConnectionString(_database));
b.UseSetting("SQLInsight:Web:Authentication", "None");
});
}
public async Task DisposeAsync()
{
await _factory.DisposeAsync();
await sql.ExecuteAsSaAsync($"ALTER DATABASE [{_database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{_database}];");
}
private static InstanceInfo Info => new()
{
ServerName = "AX01",
Version = SqlServerVersion.Parse("16.0.4135.4"),
ProductLevel = "RTM",
Edition = "Standard Edition",
EngineEdition = EngineEdition.Standard,
};
/// <summary>The open groups' keys.</summary>
private static List<string> OpenGroups(string html) =>
OpenGroup().Matches(html).Select(m => m.Groups[1].Value).ToList();
[Fact]
public async Task Menu_has_the_groups_and_opens_the_one_with_the_current_page()
{
var client = _factory.CreateClient();
var home = await client.GetStringAsync("/");
var rights = await client.GetStringAsync("/rettigheder");
var reports = await client.GetStringAsync("/rapporter");
foreach (var title in new[] { "Overvågning", "Analyse", "Konfiguration og sikkerhed", "Rapporter", "Community" })
{
Assert.Contains($"<span>{title}</span>", home, StringComparison.Ordinal);
}
Assert.Contains("<details class=\"nav-group\"", home, StringComparison.Ordinal);
Assert.Equal(["overvaagning"], OpenGroups(home));
Assert.Equal(["sikkerhed"], OpenGroups(rights));
Assert.Equal(["rapporter"], OpenGroups(reports));
Assert.DoesNotContain("Dynamics AX</span>", home, StringComparison.Ordinal); // no AX databases
Assert.Contains("nav-toggle", home, StringComparison.Ordinal); // folds away on narrow screens
}
[Fact]
public async Task Per_instance_entries_choose_the_instance_and_pages_below_an_instance_open_their_group()
{
await _repository.UpsertInstanceAsync(@"AX01\AX30", Info, "SqlClient", false, DateTimeOffset.UtcNow);
await _repository.UpsertInstanceAsync(@"AX02\AX40", Info, "SqlClient", false, DateTimeOffset.UtcNow);
var client = _factory.CreateClient();
var chooser = await client.GetStringAsync("/vaelg/konfiguration");
var configuration = await client.GetStringAsync($"/instanser/{Uri.EscapeDataString(@"AX01\AX30")}/konfiguration");
var waitType = await client.GetStringAsync($"/instanser/{Uri.EscapeDataString(@"AX01\AX30")}/ventetyper/LCK_M_X");
Assert.Contains($"/instanser/{Uri.EscapeDataString(@"AX02\AX40")}/konfiguration", chooser, StringComparison.Ordinal);
Assert.Equal(["sikkerhed"], OpenGroups(configuration));
Assert.Equal(["analyse"], OpenGroups(waitType));
}
[GeneratedRegex("<details class=\"nav-group\" open[^>]*data-nav-group=\"([a-z]+)\"")]
private static partial Regex OpenGroup();
}