test: integration tests for dashboard notes and shopping plausibility

This commit is contained in:
Jannis committed 2026-10-10 19:03:25 +02:00
1 parent 8dc923cd6e
commit 5be06b247c
2 files changed
+161

No files matched your search

@@ -0,0 +1,87 @@
using System.Net;
using System.Net.Http.Json;
using FamilyPlanner.Domain;
using FamilyPlanner.Domain.Dashboard;
using FamilyPlanner.Shared.Dashboard;
namespace FamilyPlanner.IntegrationTests;
/// <summary>Info-Kachel der Startseite: alle sehen die Notizen, nur Eltern pflegen sie (Permission.DashboardNotesEdit).</summary>
[Collection(SettingsCollection.Name)]
public sealed class DashboardNotesTests(AppFixture fixture)
{
private static CancellationToken Ct => TestContext.Current.CancellationToken;
private static async Task<DashboardNotesDto> NotesAsync(HttpClient client) =>
(await client.GetFromJsonAsync<DashboardDto>("/api/dashboard", Ct))!.Notes!;
[Fact]
public async Task Parents_manage_notes_and_everyone_sees_them_as_text()
{
var (_, family) = await fixture.CreateSignedInUserAsync(Roles.Family, Ct);
var (_, child) = await fixture.CreateSignedInUserAsync(Roles.Child, Ct);
var (_, guest) = await fixture.CreateSignedInUserAsync(Roles.Guest, Ct);
using var _f = family;
using var _c = child;
using var _g = guest;
var title = $"Wlan {Guid.NewGuid():N}";
var created = await family.PostAsJsonAsync("/api/dashboard/notes", new SaveDashboardNoteRequest(title, "<b>geheim</b>\nZeile 2"), Ct);
Assert.Equal(HttpStatusCode.Created, created.StatusCode);
var note = (await created.Content.ReadFromJsonAsync<DashboardNoteDto>(Ct))!;
foreach (var client in new[] { family, child, guest })
{
var seen = Assert.Single((await NotesAsync(client)).Items, n => n.Id == note.Id);
Assert.Equal((title, "<b>geheim</b>\nZeile 2"), (seen.Title, seen.Text));
}
Assert.True((await NotesAsync(family)).CanEdit);
Assert.False((await NotesAsync(child)).CanEdit);
Assert.False((await NotesAsync(guest)).CanEdit);
var updated = await family.PutAsJsonAsync($"/api/dashboard/notes/{note.Id}", new SaveDashboardNoteRequest(title, "neu"), Ct);
Assert.Equal("neu", (await updated.Content.ReadFromJsonAsync<DashboardNoteDto>(Ct))!.Text);
Assert.Equal(HttpStatusCode.NoContent, (await family.DeleteAsync($"/api/dashboard/notes/{note.Id}", Ct)).StatusCode);
Assert.Equal(HttpStatusCode.NoContent, (await family.DeleteAsync($"/api/dashboard/notes/{note.Id}", Ct)).StatusCode); // idempotent
Assert.DoesNotContain((await NotesAsync(child)).Items, n => n.Id == note.Id);
Assert.Equal(HttpStatusCode.NotFound, (await family.PutAsJsonAsync($"/api/dashboard/notes/{note.Id}", new SaveDashboardNoteRequest(title, "x"), Ct)).StatusCode);
}
[Fact]
public async Task Children_and_guests_cannot_change_notes()
{
var (_, family) = await fixture.CreateSignedInUserAsync(Roles.Family, Ct);
var (_, child) = await fixture.CreateSignedInUserAsync(Roles.Child, Ct);
var (_, guest) = await fixture.CreateSignedInUserAsync(Roles.Guest, Ct);
using var _f = family;
using var _c = child;
using var _g = guest;
var note = (await (await family.PostAsJsonAsync("/api/dashboard/notes", new SaveDashboardNoteRequest("Schutz", "Text"), Ct))
.Content.ReadFromJsonAsync<DashboardNoteDto>(Ct))!;
foreach (var client in new[] { child, guest })
{
Assert.Equal(HttpStatusCode.Forbidden, (await client.PostAsJsonAsync("/api/dashboard/notes", new SaveDashboardNoteRequest("A", "B"), Ct)).StatusCode);
Assert.Equal(HttpStatusCode.Forbidden, (await client.PutAsJsonAsync($"/api/dashboard/notes/{note.Id}", new SaveDashboardNoteRequest("A", "B"), Ct)).StatusCode);
Assert.Equal(HttpStatusCode.Forbidden, (await client.DeleteAsync($"/api/dashboard/notes/{note.Id}", Ct)).StatusCode);
}
await family.DeleteAsync($"/api/dashboard/notes/{note.Id}", Ct);
}
[Fact]
public async Task Notes_are_validated()
{
var (_, family) = await fixture.CreateSignedInUserAsync(Roles.Family, Ct);
using var _f = family;
Assert.Equal(HttpStatusCode.BadRequest, (await family.PostAsJsonAsync("/api/dashboard/notes", new SaveDashboardNoteRequest("", "Text"), Ct)).StatusCode);
Assert.Equal(HttpStatusCode.BadRequest, (await family.PostAsJsonAsync("/api/dashboard/notes", new SaveDashboardNoteRequest("Titel", ""), Ct)).StatusCode);
Assert.Equal(HttpStatusCode.BadRequest, (await family.PostAsJsonAsync("/api/dashboard/notes",
new SaveDashboardNoteRequest(new string('t', DashboardNote.TitleMaxLength + 1), "Text"), Ct)).StatusCode);
Assert.Equal(HttpStatusCode.BadRequest, (await family.PostAsJsonAsync("/api/dashboard/notes",
new SaveDashboardNoteRequest("Titel", new string('x', DashboardNote.TextMaxLength + 1)), Ct)).StatusCode);
}
}
@@ -0,0 +1,74 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using FamilyPlanner.Domain;
using FamilyPlanner.Shared.Shopping;
namespace FamilyPlanner.IntegrationTests;
/// <summary>Einkaufsliste: „hinzugefügt von …“ und Plausibilitätsprüfung für Kinder (409 + Confirm).</summary>
[Collection(SettingsCollection.Name)]
public sealed class ShoppingPlausibilityTests(AppFixture fixture)
{
private static CancellationToken Ct => TestContext.Current.CancellationToken;
private async Task<Guid> CreateListAsync(HttpClient admin)
{
var response = await admin.PostAsJsonAsync("/api/shopping/lists", new CreateShoppingListRequest(null, $"Plaus {Guid.NewGuid():N}"[..20]), Ct);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
return (await response.Content.ReadFromJsonAsync<ShoppingListDto>(Ct))!.Id;
}
private static Task<HttpResponseMessage> AddAsync(HttpClient client, Guid listId, string text, bool confirm = false) =>
client.PostAsJsonAsync($"/api/shopping/lists/{listId}/items", new AddShoppingItemRequest(Guid.NewGuid(), text, Confirm: confirm), Ct);
[Fact]
public async Task Child_gets_a_confirmation_request_for_nonsense_and_can_confirm()
{
using var admin = await fixture.CreateAdminClientAsync(Ct);
var (_, child) = await fixture.CreateSignedInUserAsync(Roles.Child, Ct);
using var _c = child;
var listId = await CreateListAsync(admin);
var rejected = await AddAsync(child, listId, "asdfgh");
Assert.Equal(HttpStatusCode.Conflict, rejected.StatusCode);
using var body = JsonDocument.Parse(await rejected.Content.ReadAsStringAsync(Ct));
Assert.True(body.RootElement.GetProperty(ShoppingProblemExtensions.NeedsConfirmation).GetBoolean());
Assert.Empty(await child.GetFromJsonAsync<List<ShoppingItemDto>>($"/api/shopping/lists/{listId}/items", Ct) ?? []);
var confirmed = await AddAsync(child, listId, "asdfgh", confirm: true);
Assert.Equal(HttpStatusCode.Created, confirmed.StatusCode);
Assert.Equal("Asdfgh", (await confirmed.Content.ReadFromJsonAsync<ShoppingItemDto>(Ct))!.Name);
}
[Fact]
public async Task Normal_items_from_children_and_nonsense_from_parents_are_saved_directly()
{
using var admin = await fixture.CreateAdminClientAsync(Ct);
var (_, child) = await fixture.CreateSignedInUserAsync(Roles.Child, Ct);
var (_, family) = await fixture.CreateSignedInUserAsync(Roles.Family, Ct);
using var _c = child;
using var _f = family;
var listId = await CreateListAsync(admin);
Assert.Equal(HttpStatusCode.Created, (await AddAsync(child, listId, "2x Milch")).StatusCode);
Assert.Equal(HttpStatusCode.Created, (await AddAsync(family, listId, "asdfgh")).StatusCode);
Assert.Equal(HttpStatusCode.Created, (await AddAsync(admin, listId, "???")).StatusCode);
}
[Fact]
public async Task Items_carry_the_name_of_who_added_them()
{
using var admin = await fixture.CreateAdminClientAsync(Ct);
var (user, child) = await fixture.CreateSignedInUserAsync(Roles.Child, Ct);
using var _c = child;
var listId = await CreateListAsync(admin);
var added = (await (await AddAsync(child, listId, "Butter")).Content.ReadFromJsonAsync<ShoppingItemDto>(Ct))!;
Assert.Equal(user.DisplayName, added.CreatedByName);
var listed = (await admin.GetFromJsonAsync<List<ShoppingItemDto>>($"/api/shopping/lists/{listId}/items", Ct))!;
Assert.Equal(user.DisplayName, Assert.Single(listed).CreatedByName);
}
}