using Bunit; using Marathon.UI.Components; using Marathon.UI.Services; using Marathon.UI.Tests.Support; namespace Marathon.UI.Tests.Components; public sealed class AnomalyEvidenceTests : MarathonTestContext { [Fact] public void Renders_two_columns_with_pre_and_post_kickers() { var pre = FakeAnomalyBrowsingService.MakeSnapshot(); var post = FakeAnomalyBrowsingService.MakeSnapshot( rate1: 4.00m, rate2: 1.30m, p1: 0.245m, p2: 0.755m, favourite: AnomalyFavourite.Side2); var cut = RenderComponent(p => p .Add(e => e.Pre, pre) .Add(e => e.Post, post) .Add(e => e.SuspensionGapSeconds, 90) .Add(e => e.IsTwoWay, true)); cut.Markup.Should().Contain("Anomaly.Evidence.Pre"); cut.Markup.Should().Contain("Anomaly.Evidence.Post"); cut.FindAll(".m-evidence__col").Count.Should().Be(2); } [Fact] public void Highlights_favourite_swap_when_sides_differ() { var pre = FakeAnomalyBrowsingService.MakeSnapshot(favourite: AnomalyFavourite.Side1); var post = FakeAnomalyBrowsingService.MakeSnapshot(favourite: AnomalyFavourite.Side2); var cut = RenderComponent(p => p .Add(e => e.Pre, pre) .Add(e => e.Post, post) .Add(e => e.SuspensionGapSeconds, 90) .Add(e => e.IsTwoWay, true)); cut.FindAll("[data-test=favourite-swap]").Should().NotBeEmpty(); cut.Markup.Should().Contain("Anomaly.Evidence.FavouriteSwap"); } [Fact] public void Hides_favourite_swap_callout_when_favourite_unchanged() { var pre = FakeAnomalyBrowsingService.MakeSnapshot(favourite: AnomalyFavourite.Side1); var post = FakeAnomalyBrowsingService.MakeSnapshot(favourite: AnomalyFavourite.Side1); var cut = RenderComponent(p => p .Add(e => e.Pre, pre) .Add(e => e.Post, post) .Add(e => e.SuspensionGapSeconds, 90) .Add(e => e.IsTwoWay, true)); cut.FindAll("[data-test=favourite-swap]").Should().BeEmpty(); } [Fact] public void Two_way_market_skips_draw_row() { var pre = FakeAnomalyBrowsingService.MakeSnapshot(rateDraw: null, pDraw: null); var post = FakeAnomalyBrowsingService.MakeSnapshot(rateDraw: null, pDraw: null, favourite: AnomalyFavourite.Side2); var cut = RenderComponent(p => p .Add(e => e.Pre, pre) .Add(e => e.Post, post) .Add(e => e.SuspensionGapSeconds, 60) .Add(e => e.IsTwoWay, true)); // 2-way → 4 rows total (2 cols × 2 sides), not 6. cut.FindAll(".m-evidence__row").Count.Should().Be(4); cut.Markup.Should().NotContain("Detail.Chart.Draw"); } [Fact] public void Three_way_market_includes_draw_row_in_each_column() { var pre = FakeAnomalyBrowsingService.MakeSnapshot(rateDraw: 3.30m, pDraw: 0.30m); var post = FakeAnomalyBrowsingService.MakeSnapshot(rateDraw: 3.20m, pDraw: 0.31m, favourite: AnomalyFavourite.Draw); var cut = RenderComponent(p => p .Add(e => e.Pre, pre) .Add(e => e.Post, post) .Add(e => e.SuspensionGapSeconds, 120) .Add(e => e.IsTwoWay, false)); // 3-way → 6 rows total (2 cols × 3 sides). cut.FindAll(".m-evidence__row").Count.Should().Be(6); cut.Markup.Should().Contain("Detail.Chart.Draw"); } [Fact] public void Renders_suspension_duration_label() { var pre = FakeAnomalyBrowsingService.MakeSnapshot(); var post = FakeAnomalyBrowsingService.MakeSnapshot(favourite: AnomalyFavourite.Side2); var cut = RenderComponent(p => p .Add(e => e.Pre, pre) .Add(e => e.Post, post) .Add(e => e.SuspensionGapSeconds, 134) .Add(e => e.IsTwoWay, true)); cut.Markup.Should().Contain("Anomaly.Evidence.SuspensionDuration"); // 134s -> "2m 14s" cut.Markup.Should().Contain("2m 14s"); } }