9f090cec1f
* Pages/Results/ResultsList.razor — completed-events list with date range, sport/winner filter, search, footer count. * Pages/Results/ResultsLoader.razor — driver page with two modes (load all in range / load selected events), live progress reporting via IProgress<PullResultsProgress>, summary line, cancellable. * Replaces the Phase 5 Pages/Results.razor placeholder. Service layer: * IResultsBrowsingService + ResultsBrowsingService (Scoped, mirrors the Event/Anomaly browsing-service pattern). Reads IResultRepository + IEventRepository, projects to immutable view-model records. * UiServicesExtensions: registers ResultsBrowsingService; also fixes an unrelated localization resolver bug (drop ResourcesPath since SharedResource lives in the Marathon.UI.Resources namespace already). Localization: * 41 new Results.* keys (RU+EN parity) covering both pages, filter chips, loader modes, progress states, and footer copy. Tests: * ResultsListTests + ResultsLoaderTests — 22 new bUnit tests covering filter narrowing, mode switching, progress aggregation, and empty states. * FakeResultsBrowsingService support type for tests. * MarathonTestContext registers the fake; TestData adds factories for EventResult/EventResultListItem.
97 lines
3.3 KiB
C#
97 lines
3.3 KiB
C#
using AngleSharp.Dom;
|
|
using Bunit;
|
|
using Marathon.Domain.Enums;
|
|
using Marathon.UI.Pages.Results;
|
|
using Marathon.UI.Tests.Support;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace Marathon.UI.Tests.Pages.Results;
|
|
|
|
public sealed class ResultsListTests : MarathonTestContext
|
|
{
|
|
[Fact]
|
|
public void Renders_seeded_results()
|
|
{
|
|
Browsing.SportCodes.AddRange(new[] { 11, 6 });
|
|
Results.ResultItems.AddRange(new[]
|
|
{
|
|
TestData.ResultListItem(id: "EV-1", side1: "Arsenal", side2: "Chelsea", side1Score: 2, side2Score: 1, winner: Side.Side1),
|
|
TestData.ResultListItem(id: "EV-2", side1: "Lakers", side2: "Bulls", sport: 6, side1Score: 105, side2Score: 110, winner: Side.Side2),
|
|
});
|
|
|
|
var cut = RenderComponent<ResultsList>();
|
|
cut.WaitForAssertion(() =>
|
|
{
|
|
var rows = cut.FindAll("[data-test=results-row]");
|
|
rows.Count.Should().Be(2);
|
|
});
|
|
|
|
cut.Markup.Should().Contain("Arsenal");
|
|
cut.Markup.Should().Contain("Lakers");
|
|
var scoreCells = cut.FindAll("[data-test=results-score]").Select(e => e.TextContent.Trim()).ToList();
|
|
scoreCells.Should().Contain("2:1");
|
|
scoreCells.Should().Contain("105:110");
|
|
}
|
|
|
|
[Fact]
|
|
public void Renders_empty_state_when_no_results()
|
|
{
|
|
var cut = RenderComponent<ResultsList>();
|
|
cut.WaitForAssertion(() =>
|
|
{
|
|
cut.Markup.Should().Contain("Results.Empty");
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Winner_filter_narrows_to_selected_side()
|
|
{
|
|
Results.ResultItems.AddRange(new[]
|
|
{
|
|
TestData.ResultListItem(id: "EV-1", side1: "Arsenal", side2: "Chelsea", winner: Side.Side1),
|
|
TestData.ResultListItem(id: "EV-2", side1: "Real", side2: "Barca", winner: Side.Side2),
|
|
TestData.ResultListItem(id: "EV-3", side1: "City", side2: "Spurs", winner: Side.Draw),
|
|
});
|
|
|
|
var cut = RenderComponent<ResultsList>();
|
|
cut.WaitForAssertion(() => cut.FindAll("[data-test=results-row]").Count.Should().Be(3));
|
|
|
|
// Filter by Side2 winner — expect only ev-2
|
|
cut.Find("[data-test=results-winner-filter]").Change("Side2");
|
|
|
|
cut.WaitForAssertion(() =>
|
|
{
|
|
Results.LastResultsFilter!.WinnerSide.Should().Be(Side.Side2);
|
|
cut.FindAll("[data-test=results-row]").Count.Should().Be(1);
|
|
cut.Markup.Should().Contain("Real");
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Open_loader_button_navigates_to_loader_route()
|
|
{
|
|
var nav = Services.GetRequiredService<NavigationManager>();
|
|
|
|
var cut = RenderComponent<ResultsList>();
|
|
cut.WaitForAssertion(() => cut.Find("[data-test=results-open-loader]"));
|
|
cut.Find("[data-test=results-open-loader]").Click();
|
|
|
|
nav.Uri.Should().EndWith("/results/load");
|
|
}
|
|
|
|
[Fact]
|
|
public void Clicking_a_row_navigates_to_event_detail()
|
|
{
|
|
Results.ResultItems.Add(TestData.ResultListItem(id: "EV-42"));
|
|
var nav = Services.GetRequiredService<NavigationManager>();
|
|
|
|
var cut = RenderComponent<ResultsList>();
|
|
cut.WaitForAssertion(() => cut.Find("[data-test=results-row]"));
|
|
|
|
cut.Find("[data-test=results-row]").Click();
|
|
|
|
nav.Uri.Should().Contain("/events/EV-42");
|
|
}
|
|
}
|