using System.Net;
using MeterVault.Infrastructure.Import;
using MeterVault.Infrastructure.Persistence;
using MeterVault.Integration.Tests.Costing;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using static MeterVault.Integration.Tests.Costing.CostSandbox;
namespace MeterVault.Integration.Tests.Overview;
///
/// The Overview page (brief §7.1) rendered by the real app on the frozen clock of
/// (server prerender, which reads the initial load): this month to date of the seeded instance says there is no data
/// and offers the latest month as its own period instead of showing it; the previous year shows the sheet's bill with
/// the energy type cards, the attention item with its tariff link, the change table and the composition, in English and
/// German; a manual-cost-only instance shows its month without a meter. Interactive behaviour (chart, toggles) is covered
/// by the pure tests and the browser check.
///
[Collection("Timescale")]
public sealed class OverviewPageTests(TimescaleFixture fx) : IAsyncLifetime
{
public async Task InitializeAsync()
{
await using var db = fx.CreateContext();
await ClearDataAsync(db);
}
public async Task DisposeAsync()
{
await using var db = fx.CreateContext();
await ClearDataAsync(db);
}
[Fact]
public async Task The_seeded_overview_explains_an_empty_month_and_shows_the_previous_year_s_bill()
{
await LoadReferenceDataAsync();
int strom;
await using (var db = fx.CreateContext())
{
strom = await db.EnergyTypes.Where(t => t.Key == "electricity").Select(t => (int)t.Id).FirstAsync();
}
using var app = new FrozenApp(fx.ConnectionString);
// Month to date (the default): no data, the dates that have data, and the latest month as its own period — the
// panels are not silently switched to May.
var empty = await app.GetAsync("/");
Assert.Contains("
The app on the frozen clock of ; pages come back HTML-decoded.
private sealed class FrozenApp : IDisposable
{
private readonly MeterVaultAppFactory _root;
private readonly WebApplicationFactory _app;
public FrozenApp(string connectionString)
{
_root = new MeterVaultAppFactory(connectionString);
_app = _root.WithWebHostBuilder(builder =>
builder.ConfigureTestServices(services => services.AddSingleton(new FixedTimeProvider(Now))));
}
public async Task GetAsync(string path, string culture = "en")
{
using var client = _app.CreateClient();
client.DefaultRequestHeaders.Add(
"Cookie",
CookieRequestCultureProvider.DefaultCookieName + "="
+ Uri.EscapeDataString(CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture))));
using var response = await client.GetAsync(new Uri(path, UriKind.Relative));
response.EnsureSuccessStatusCode();
return WebUtility.HtmlDecode(await response.Content.ReadAsStringAsync());
}
public void Dispose()
{
_app.Dispose();
_root.Dispose();
}
}
}