feat(usability): preserve reporting year and locate outside-period bookings (U04)

This commit is contained in:
2026-11-02 06:28:36 +01:00
parent 122d4de809
commit 9c41856b5b
16 changed files with 169 additions and 26 deletions
@@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="bunit" Version="2.13.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
<PackageReference Include="PdfPig" Version="0.1.16" />
<PackageReference Include="xunit" Version="2.9.3" />
@@ -0,0 +1,19 @@
using Duempelkas.App.Services;
using Xunit;
namespace Duempelkas.Tests;
public class ReportingPeriodTests
{
[Fact]
public void EmptyYearList_PreservesSelectedYear_AndOffersCurrentYear()
{
var period = new ReportingPeriod { Year = 2025 };
Assert.Contains(2025, period.Choices([]));
Assert.Contains(DateTime.Today.Year, period.Choices([]));
Assert.Equal("Jahr: 2025", period.Label);
period.Year = null;
Assert.Equal("Alle Jahre", period.Label);
Assert.Null(period.Year);
}
}
@@ -0,0 +1,58 @@
using Bunit;
using Duempelkas.App.Components;
using Duempelkas.App.Components.Dialogs;
using Duempelkas.App.Services;
using Duempelkas.Domain.Enums;
using Duempelkas.Infrastructure;
using Duempelkas.Infrastructure.Persistence;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Duempelkas.Tests;
public class YearNavigationTests
{
[Fact]
public async Task Navigation_PreservesYear_AndOutsideBookingOffersReturn()
{
using var context = new BunitContext();
var connectionString = $"Data Source=year-ui-{Guid.NewGuid():N};Mode=Memory;Cache=Shared";
using var anchor = new SqliteConnection(connectionString);
anchor.Open();
context.Services.AddInfrastructure(connectionString);
context.JSInterop.Mode = JSRuntimeMode.Loose;
using (var db = context.Services.GetRequiredService<IDbContextFactory<FinanceDbContext>>().CreateDbContext())
{
db.Database.EnsureCreated();
db.Accounts.Add(new() { Name = "Testkasse" });
db.SaveChanges();
await context.Services.GetRequiredService<IEntryService>().CreateEntryAsync(db.Accounts.Single().Id,
EntryType.Income, new(2025, 1, 1), "Vorjahr", 10m);
}
context.Services.GetRequiredService<ReportingPeriod>().Year = 2025;
var page = context.Render<Routes>();
page.WaitForAssertion(() => Assert.Contains("Jahr: 2025", page.Markup));
page.Find(".account-card").Click();
page.WaitForAssertion(() => Assert.Contains("Vorjahr", page.Markup));
page.FindAll("button").Single(b => b.TextContent.Contains("Zurück")).Click();
page.WaitForAssertion(() => Assert.Contains("Jahr: 2025", page.Markup));
page.Find(".account-card").Click();
page.WaitForElement(".summary-section");
page.FindAll("button").Single(b => b.TextContent.Trim() == "Buchung").Click();
var dialog = page.FindComponent<AddEntryDialog>();
dialog.Find("input[type=date]").Change("2026-01-02");
dialog.Find("input[type=text]").Change("Außerhalb");
dialog.Find("input[type=number]").Change("12.50");
Assert.Contains("außerhalb", dialog.Markup);
Assert.True(dialog.Find("button.btn-success").HasAttribute("disabled"));
dialog.Find("input[type=checkbox]").Change(true);
dialog.Find("button.btn-success").Click();
page.WaitForAssertion(() => Assert.Contains("Buchung im Jahr 2026 anzeigen", page.Markup));
Assert.DoesNotContain("Außerhalb", page.Find("table").TextContent);
page.FindAll("button").Single(b => b.TextContent.Contains("Buchung im Jahr 2026 anzeigen")).Click();
page.WaitForAssertion(() => Assert.Contains("Außerhalb", page.Find("table").TextContent));
Assert.Equal(2026, context.Services.GetRequiredService<ReportingPeriod>().Year);
}
}