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>
90 lines
4 KiB
C#
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();
|
|
}
|