using Bunit; using Marathon.UI.Pages.Anomalies; using Marathon.UI.Services; using Marathon.UI.Tests.Support; namespace Marathon.UI.Tests.Pages.Anomalies; public sealed class AnomalyFeedTests : MarathonTestContext { [Fact] public void Renders_seeded_anomaly_cards() { AnomalyBrowsing.SportCodes.AddRange(new[] { 6, 11 }); AnomalyBrowsing.Items.AddRange(new[] { FakeAnomalyBrowsingService.MakeItem(title: "Lakers vs Bulls", sport: 6, score: 0.65m), FakeAnomalyBrowsingService.MakeItem(title: "Arsenal vs Chelsea", sport: 11, score: 0.40m), }); var cut = RenderComponent(); cut.WaitForAssertion(() => { cut.FindAll("[data-test=anomaly-card]").Count.Should().Be(2); cut.Markup.Should().Contain("Lakers vs Bulls"); cut.Markup.Should().Contain("Arsenal vs Chelsea"); }); } [Fact] public void Renders_empty_state_when_no_anomalies_match_filter() { var cut = RenderComponent(); cut.WaitForAssertion(() => { cut.FindAll("[data-test=anomaly-empty]").Should().NotBeEmpty(); cut.Markup.Should().Contain("Anomaly.Empty.NoneInRange"); }); } [Fact] public void Severity_chip_filter_narrows_the_list() { AnomalyBrowsing.Items.AddRange(new[] { FakeAnomalyBrowsingService.MakeItem(title: "High event", score: 0.70m), FakeAnomalyBrowsingService.MakeItem(title: "Low event", score: 0.32m), }); var cut = RenderComponent(); cut.WaitForAssertion(() => cut.FindAll("[data-test=anomaly-card]").Count.Should().Be(2)); // Click the High severity chip. var highChip = cut.FindAll("[data-test=severity-chip]") .First(e => e.GetAttribute("data-severity") == "High"); highChip.Click(); cut.WaitForAssertion(() => { var cards = cut.FindAll("[data-test=anomaly-card]"); cards.Count.Should().Be(1); cut.Markup.Should().Contain("High event"); cut.Markup.Should().NotContain("Low event"); AnomalyBrowsing.LastFilter.Should().NotBeNull(); AnomalyBrowsing.LastFilter!.MinSeverity.Should().Be(AnomalySeverity.High); }); } [Fact] public void Sport_chip_filter_narrows_the_list() { AnomalyBrowsing.SportCodes.AddRange(new[] { 6, 11 }); AnomalyBrowsing.Items.AddRange(new[] { FakeAnomalyBrowsingService.MakeItem(title: "Lakers vs Bulls", sport: 6, score: 0.55m), FakeAnomalyBrowsingService.MakeItem(title: "Arsenal vs Chelsea", sport: 11, score: 0.55m), }); var cut = RenderComponent(); cut.WaitForAssertion(() => cut.FindAll("[data-test=anomaly-card]").Count.Should().Be(2)); // Pick the basketball chip (sport=6). var sportChips = cut.FindAll("[data-test=sport-chip]"); sportChips.Should().NotBeEmpty(); sportChips.First().Click(); cut.WaitForAssertion(() => { AnomalyBrowsing.LastFilter.Should().NotBeNull(); AnomalyBrowsing.LastFilter!.SportCodes.Should().NotBeNull(); AnomalyBrowsing.LastFilter!.SportCodes!.Should().HaveCount(1); }); } [Fact] public void Mark_read_button_clears_unread_count_in_state() { AnomalyState.SetUnreadCount(5); AnomalyBrowsing.UnreadCount = 0; AnomalyBrowsing.Items.Add(FakeAnomalyBrowsingService.MakeItem()); var cut = RenderComponent(); cut.WaitForAssertion(() => cut.FindAll("[data-test=anomaly-card]").Count.Should().Be(1)); cut.Find("[data-test=mark-read]").Click(); AnomalyState.UnreadCount.Should().Be(0); AnomalyState.LastSeenUtc.Should().BeAfter(DateTimeOffset.MinValue); } }