feat(ui): health dashboard shows metrics-stale badge and offline-since timestamp
This commit is contained in:
@@ -82,6 +82,11 @@ public class HealthPageTests : BunitContext
|
||||
.Returns(Task.FromResult<IReadOnlyList<Site>>(new List<Site>()));
|
||||
Services.AddSingleton(siteRepo);
|
||||
|
||||
// PLAN-01 Task 14 — the Health page now shows the metrics-stale badge with
|
||||
// a tooltip naming the configured MetricsStaleTimeout, so it injects the
|
||||
// health-monitoring options.
|
||||
Services.AddSingleton(Options.Create(new HealthMonitoringOptions()));
|
||||
|
||||
// Audit Log (#23) M7 Bundle E — the Health page now also fetches the
|
||||
// Audit KPI snapshot. Stub it with an empty point-in-time reading so
|
||||
// the existing assertions (Notification Outbox tiles, Online/Offline
|
||||
@@ -275,6 +280,62 @@ public class HealthPageTests : BunitContext
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Renders_MetricsStaleBadge_ForOnlineButStaleSite()
|
||||
{
|
||||
// PLAN-01 Task 14: a site that is online (heartbeating) but whose report
|
||||
// pipeline died shows a distinct "Metrics stale" warning badge.
|
||||
SeedStates(new SiteHealthState
|
||||
{
|
||||
SiteId = "site-a",
|
||||
IsOnline = true,
|
||||
IsMetricsStale = true,
|
||||
LastHeartbeatAt = DateTimeOffset.UtcNow,
|
||||
LastReportReceivedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
|
||||
});
|
||||
|
||||
var cut = Render<HealthPage>();
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
{
|
||||
Assert.Contains("Metrics stale", cut.Markup);
|
||||
// The badge uses the page's Bootstrap warning style.
|
||||
Assert.Contains("bg-warning", cut.Markup);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Renders_OfflineSince_ForOfflineSiteWithStatusChange()
|
||||
{
|
||||
var changedAt = new DateTimeOffset(2026, 7, 8, 12, 34, 56, TimeSpan.Zero);
|
||||
SeedStates(new SiteHealthState
|
||||
{
|
||||
SiteId = "site-a",
|
||||
IsOnline = false,
|
||||
LastHeartbeatAt = changedAt,
|
||||
LastStatusChangeAt = changedAt,
|
||||
});
|
||||
|
||||
var cut = Render<HealthPage>();
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
{
|
||||
Assert.Contains("offline since", cut.Markup);
|
||||
// The "u" (universal sortable) format the page renders the flip with.
|
||||
Assert.Contains(changedAt.ToString("u"), cut.Markup);
|
||||
});
|
||||
}
|
||||
|
||||
// Re-seeds the aggregator substitute with fully-specified states (as opposed
|
||||
// to SeedSites' minimal online placeholders).
|
||||
private void SeedStates(params SiteHealthState[] states)
|
||||
{
|
||||
var aggregator = Substitute.For<ICentralHealthAggregator>();
|
||||
aggregator.GetAllSiteStates()
|
||||
.Returns(states.ToDictionary(s => s.SiteId));
|
||||
Services.AddSingleton(aggregator);
|
||||
}
|
||||
|
||||
// Re-seeds the aggregator substitute so the trend panel's site selector has
|
||||
// options. Each site id maps to a minimal online SiteHealthState (a null
|
||||
// report is fine — the trend panel keys off the site ids, not the report).
|
||||
|
||||
Reference in New Issue
Block a user