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.
134 lines
4.0 KiB
C#
134 lines
4.0 KiB
C#
using Marathon.Domain.Entities;
|
|
using Marathon.Domain.Enums;
|
|
using Marathon.Domain.ValueObjects;
|
|
using Marathon.UI.Services;
|
|
|
|
namespace Marathon.UI.Tests.Support;
|
|
|
|
internal static class TestData
|
|
{
|
|
public static readonly TimeSpan Moscow = TimeSpan.FromHours(3);
|
|
|
|
public static EventListItem ListItem(
|
|
string id = "100001",
|
|
int sport = 11,
|
|
string country = "ENG",
|
|
string league = "Premier League",
|
|
string side1 = "Arsenal",
|
|
string side2 = "Chelsea",
|
|
decimal? win1 = 1.85m,
|
|
decimal? draw = 3.40m,
|
|
decimal? win2 = 4.20m,
|
|
DateTimeOffset? scheduled = null)
|
|
=> new(
|
|
new EventId(id),
|
|
new SportCode(sport),
|
|
country,
|
|
league,
|
|
side1,
|
|
side2,
|
|
scheduled ?? MoscowToday(20),
|
|
win1,
|
|
draw,
|
|
win2,
|
|
DateTimeOffset.UtcNow,
|
|
OddsSource.PreMatch);
|
|
|
|
/// <summary>Today at <paramref name="hour"/>:00 in Moscow (+03:00).</summary>
|
|
public static DateTimeOffset MoscowToday(int hour)
|
|
{
|
|
var nowMoscow = DateTimeOffset.UtcNow.ToOffset(Moscow);
|
|
var midnight = new DateTimeOffset(
|
|
nowMoscow.Year, nowMoscow.Month, nowMoscow.Day,
|
|
0, 0, 0, Moscow);
|
|
return midnight.AddHours(hour);
|
|
}
|
|
|
|
public static EventResultListItem ResultListItem(
|
|
string id = "100001",
|
|
int sport = 11,
|
|
string country = "ENG",
|
|
string league = "Premier League",
|
|
string side1 = "Arsenal",
|
|
string side2 = "Chelsea",
|
|
int side1Score = 2,
|
|
int side2Score = 1,
|
|
Side winner = Side.Side1,
|
|
DateTimeOffset? scheduled = null,
|
|
DateTimeOffset? completed = null)
|
|
=> new(
|
|
new EventId(id),
|
|
new SportCode(sport),
|
|
country,
|
|
league,
|
|
side1,
|
|
side2,
|
|
scheduled ?? MoscowToday(20),
|
|
side1Score,
|
|
side2Score,
|
|
winner,
|
|
completed ?? MoscowToday(22));
|
|
|
|
public static EventResultCandidate ResultCandidate(
|
|
string id = "100001",
|
|
int sport = 11,
|
|
string country = "ENG",
|
|
string league = "Premier League",
|
|
string side1 = "Arsenal",
|
|
string side2 = "Chelsea",
|
|
DateTimeOffset? scheduled = null)
|
|
=> new(
|
|
new EventId(id),
|
|
new SportCode(sport),
|
|
country,
|
|
league,
|
|
side1,
|
|
side2,
|
|
scheduled ?? MoscowToday(20));
|
|
|
|
public static EventDetail Detail(
|
|
string id = "100001",
|
|
params OddsTimelinePoint[] timeline)
|
|
{
|
|
var moscow = Moscow;
|
|
var scheduled = MoscowToday(20);
|
|
var timelinePts = timeline.Length > 0
|
|
? timeline.ToList()
|
|
: new List<OddsTimelinePoint>
|
|
{
|
|
new(scheduled.AddMinutes(-30), 1.90m, 3.30m, 4.10m),
|
|
new(scheduled.AddMinutes(-15), 1.85m, 3.40m, 4.20m),
|
|
};
|
|
|
|
var matchBoard = new EventScopeBoard(MatchScope.Instance, new List<BetRow>
|
|
{
|
|
new(BetType.Win, Side.Side1, null, 1.85m),
|
|
new(BetType.Draw, Side.Draw, null, 3.40m),
|
|
new(BetType.Win, Side.Side2, null, 4.20m),
|
|
});
|
|
var period1Board = new EventScopeBoard(new PeriodScope(1), new List<BetRow>
|
|
{
|
|
new(BetType.Win, Side.Side1, null, 2.10m),
|
|
new(BetType.Win, Side.Side2, null, 3.10m),
|
|
new(BetType.Total, Side.More, 1.5m, 1.95m),
|
|
new(BetType.Total, Side.Less, 1.5m, 1.95m),
|
|
});
|
|
|
|
var history = timelinePts.Select(p =>
|
|
new SnapshotHistoryEntry(p.At, OddsSource.PreMatch, 8, p.Win1Rate, p.DrawRate, p.Win2Rate)
|
|
).ToList();
|
|
|
|
return new EventDetail(
|
|
new EventId(id),
|
|
new SportCode(11),
|
|
"ENG",
|
|
"Premier League",
|
|
"Arsenal",
|
|
"Chelsea",
|
|
scheduled,
|
|
new[] { matchBoard, period1Board },
|
|
timelinePts,
|
|
history);
|
|
}
|
|
}
|