178 lines
7.1 KiB
C#
178 lines
7.1 KiB
C#
using Bunit;
|
|
using Bunit.TestDoubles;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using ScadaLink.CentralUI.Components.Health;
|
|
using ScadaLink.Commons.Messages.Audit;
|
|
|
|
namespace ScadaLink.CentralUI.Tests.Components.Health;
|
|
|
|
/// <summary>
|
|
/// bUnit tests for <see cref="SiteCallKpiTiles"/> (Site Call Audit #22, Task 7).
|
|
/// The component renders three Bootstrap-card tiles — Buffered, Stuck, Parked —
|
|
/// from a single <see cref="SiteCallKpiResponse"/> snapshot. The tests pin:
|
|
///
|
|
/// <list type="bullet">
|
|
/// <item>Three-tile render contract (data-test attributes for stable selectors).</item>
|
|
/// <item>Tile values render the snapshot's counters.</item>
|
|
/// <item>Threshold borders fire correctly — danger on Parked > 0, warning
|
|
/// on Stuck > 0, none when those counts are zero, none on Buffered.</item>
|
|
/// <item>Unavailable snapshot renders em dashes plus the error message.</item>
|
|
/// <item>Tile clicks navigate to the correct pre-filtered Site Calls report URL.</item>
|
|
/// </list>
|
|
/// </summary>
|
|
public class SiteCallKpiTilesTests : BunitContext
|
|
{
|
|
private static SiteCallKpiResponse MakeSnapshot(int buffered, int parked, int stuck) =>
|
|
new(
|
|
CorrelationId: "k",
|
|
Success: true,
|
|
ErrorMessage: null,
|
|
BufferedCount: buffered,
|
|
ParkedCount: parked,
|
|
FailedLastInterval: 0,
|
|
DeliveredLastInterval: 0,
|
|
OldestPendingAge: null,
|
|
StuckCount: stuck);
|
|
|
|
[Fact]
|
|
public void Renders_ThreeTiles_FromSnapshot()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 120, parked: 3, stuck: 7))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
// Three stable data-test selectors — the contract for both these tests
|
|
// and any future Playwright sweep.
|
|
Assert.Contains("data-test=\"site-call-kpi-buffered\"", cut.Markup);
|
|
Assert.Contains("data-test=\"site-call-kpi-stuck\"", cut.Markup);
|
|
Assert.Contains("data-test=\"site-call-kpi-parked\"", cut.Markup);
|
|
|
|
// Tile values render the snapshot's counters.
|
|
Assert.Contains(">120<", cut.Markup); // buffered
|
|
Assert.Contains(">7<", cut.Markup); // stuck
|
|
Assert.Contains(">3<", cut.Markup); // parked
|
|
}
|
|
|
|
[Fact]
|
|
public void UnavailableSnapshot_RendersEmDashes_AndErrorMessage()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, (SiteCallKpiResponse?)null)
|
|
.Add(c => c.IsAvailable, false)
|
|
.Add(c => c.ErrorMessage, "site call repository unavailable"));
|
|
|
|
// All three tiles show em dashes — em dash (U+2014) "—" must appear.
|
|
Assert.Contains("—", cut.Markup);
|
|
// Inline error message renders below.
|
|
Assert.Contains("Site Call KPIs unavailable", cut.Markup);
|
|
Assert.Contains("site call repository unavailable", cut.Markup);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParkedTile_GetsDangerBorder_WhenParkedAboveZero()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 0, parked: 4, stuck: 0))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-parked\"]");
|
|
Assert.Contains("border-danger", tile.GetAttribute("class") ?? string.Empty);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParkedTile_NoDangerBorder_WhenParkedZero()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 9, parked: 0, stuck: 0))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-parked\"]");
|
|
Assert.DoesNotContain("border-danger", tile.GetAttribute("class") ?? string.Empty);
|
|
}
|
|
|
|
[Fact]
|
|
public void StuckTile_GetsWarningBorder_WhenStuckAboveZero()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 0, parked: 0, stuck: 6))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-stuck\"]");
|
|
Assert.Contains("border-warning", tile.GetAttribute("class") ?? string.Empty);
|
|
// Warning, not danger — Stuck is the softer signal.
|
|
Assert.DoesNotContain("border-danger", tile.GetAttribute("class") ?? string.Empty);
|
|
}
|
|
|
|
[Fact]
|
|
public void StuckTile_NoWarningBorder_WhenStuckZero()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 9, parked: 0, stuck: 0))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-stuck\"]");
|
|
Assert.DoesNotContain("border-warning", tile.GetAttribute("class") ?? string.Empty);
|
|
}
|
|
|
|
[Fact]
|
|
public void BufferedTile_HasNoThresholdBorder_EvenWithHighCount()
|
|
{
|
|
// A non-zero buffer is normal operation — the Buffered tile is a plain
|
|
// count tile and never gets a danger/warning border.
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 5000, parked: 0, stuck: 0))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-buffered\"]");
|
|
var cls = tile.GetAttribute("class") ?? string.Empty;
|
|
Assert.DoesNotContain("border-danger", cls);
|
|
Assert.DoesNotContain("border-warning", cls);
|
|
}
|
|
|
|
[Fact]
|
|
public void BufferedTile_Click_NavigatesToUnfilteredSiteCallsReport()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 50, parked: 0, stuck: 0))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var nav = (BunitNavigationManager)Services.GetRequiredService<NavigationManager>();
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-buffered\"]");
|
|
tile.Click();
|
|
|
|
// Unfiltered /site-calls/report — no query string.
|
|
Assert.EndsWith("/site-calls/report", nav.Uri);
|
|
}
|
|
|
|
[Fact]
|
|
public void StuckTile_Click_NavigatesToSiteCallsReport_WithStuckFilter()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 0, parked: 0, stuck: 6))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var nav = (BunitNavigationManager)Services.GetRequiredService<NavigationManager>();
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-stuck\"]");
|
|
tile.Click();
|
|
|
|
// Spec: Stuck tile drills into the report's "stuck only" filter.
|
|
Assert.Contains("/site-calls/report?stuck=true", nav.Uri);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParkedTile_Click_NavigatesToSiteCallsReport_WithParkedStatusFilter()
|
|
{
|
|
var cut = Render<SiteCallKpiTiles>(p => p
|
|
.Add(c => c.Snapshot, MakeSnapshot(buffered: 0, parked: 4, stuck: 0))
|
|
.Add(c => c.IsAvailable, true));
|
|
|
|
var nav = (BunitNavigationManager)Services.GetRequiredService<NavigationManager>();
|
|
var tile = cut.Find("[data-test=\"site-call-kpi-parked\"]");
|
|
tile.Click();
|
|
|
|
// Spec: Parked tile drills into ?status=Parked.
|
|
Assert.Contains("/site-calls/report?status=Parked", nav.Uri);
|
|
}
|
|
}
|