Add comprehensive backend test suite and helper access

This commit is contained in:
2026-02-05 18:03:50 +01:00
parent 330d87b432
commit 912da11809
11 changed files with 591 additions and 4 deletions

View File

@@ -0,0 +1,159 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using GameList.Domain;
using GameList.Tests.Support;
namespace GameList.Tests;
public class AdminTests
{
[Fact]
public async Task Admin_vote_status_marks_ready_when_all_finalized()
{
using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
await admin.PostAsJsonAsync("/api/me/phase/next", new { }); // move to Vote
var p1 = factory.CreateClientWithCookies();
await p1.RegisterAsync("alice");
var p2 = factory.CreateClientWithCookies();
await p2.RegisterAsync("bob");
await p2.PostAsJsonAsync("/api/me/phase/next", new { });
var s1 = await p1.CreateSuggestionAsync("A");
await p1.PostAsJsonAsync("/api/me/phase/next", new { });
await p1.PostAsJsonAsync("/api/votes", new { SuggestionId = s1, Score = 5 });
await p1.PostAsJsonAsync("/api/votes/finalize", new { Final = true });
await p2.PostAsJsonAsync("/api/votes", new { SuggestionId = s1, Score = 7 });
await p2.PostAsJsonAsync("/api/votes/finalize", new { Final = true });
await admin.PostAsJsonAsync("/api/votes/finalize", new { Final = true });
var status = await admin.GetFromJsonAsync<JsonElement>("/api/admin/vote-status");
Assert.True(status.GetProperty("ready").GetBoolean());
Assert.Equal(0, status.GetProperty("waiting").GetArrayLength());
}
[Fact]
public async Task Grant_joker_only_in_vote_phase()
{
using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
var p = factory.CreateClientWithCookies();
await p.RegisterAsync("player");
var give = await admin.PostAsJsonAsync("/api/admin/joker", new { playerId = (await p.GetProfileIdAsync()) });
Assert.Equal(HttpStatusCode.BadRequest, give.StatusCode);
}
[Fact]
public async Task Delete_player_cascades_suggestions_and_votes()
{
using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
var player = factory.CreateClientWithCookies();
await player.RegisterAsync("deleteme");
var suggestionId = await player.CreateSuggestionAsync("DeleteGame");
await player.PostAsJsonAsync("/api/me/phase/next", new { });
await player.PostAsJsonAsync("/api/votes", new { SuggestionId = suggestionId, Score = 8 });
var resp = await admin.DeleteAsync($"/api/admin/players/{await player.GetProfileIdAsync()}");
resp.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(async db =>
{
Assert.Single(db.Players); // admin remains
Assert.Empty(db.Suggestions);
Assert.Empty(db.Votes);
});
}
[Fact]
public async Task Link_suggestions_errors_on_same_id_and_already_linked()
{
using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
var player = factory.CreateClientWithCookies();
await player.RegisterAsync("linker");
var a = await player.CreateSuggestionAsync("Game A");
var b = await player.CreateSuggestionAsync("Game B");
await player.PostAsJsonAsync("/api/me/phase/next", new { });
await admin.PostAsJsonAsync("/api/me/phase/next", new { });
var same = await admin.PostAsJsonAsync("/api/admin/link-suggestions", new { SourceSuggestionId = a, TargetSuggestionId = a });
Assert.Equal(HttpStatusCode.BadRequest, same.StatusCode);
var first = await admin.PostAsJsonAsync("/api/admin/link-suggestions", new { SourceSuggestionId = a, TargetSuggestionId = b });
first.EnsureSuccessStatusCode();
var already = await admin.PostAsJsonAsync("/api/admin/link-suggestions", new { SourceSuggestionId = a, TargetSuggestionId = b });
Assert.Equal(HttpStatusCode.BadRequest, already.StatusCode);
}
[Fact]
public async Task Unlink_suggestions_clears_group_votes()
{
using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
var player = factory.CreateClientWithCookies();
await player.RegisterAsync("unlinker");
var a = await player.CreateSuggestionAsync("Game A");
var b = await player.CreateSuggestionAsync("Game B");
await player.PostAsJsonAsync("/api/me/phase/next", new { });
await admin.PostAsJsonAsync("/api/me/phase/next", new { });
await admin.PostAsJsonAsync("/api/admin/link-suggestions", new { SourceSuggestionId = a, TargetSuggestionId = b });
await player.PostAsJsonAsync("/api/votes", new { SuggestionId = a, Score = 6 });
var resp = await admin.PostAsJsonAsync("/api/admin/unlink-suggestions", new { suggestionId = a });
resp.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(async db =>
{
Assert.Empty(db.Votes);
Assert.All(db.Suggestions, s => Assert.Null(s.ParentSuggestionId));
});
}
[Fact]
public async Task Reset_and_factory_reset_clear_state()
{
using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
var player = factory.CreateClientWithCookies();
await player.RegisterAsync("player");
await player.CreateSuggestionAsync("Keep");
var reset = await admin.PostAsJsonAsync("/api/admin/reset", new { });
reset.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(async db =>
{
Assert.Empty(db.Suggestions);
Assert.Empty(db.Votes);
Assert.All(db.Players, p => Assert.Equal(Phase.Suggest, p.CurrentPhase));
});
var factoryReset = await admin.PostAsJsonAsync("/api/admin/factory-reset", new { });
factoryReset.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(async db =>
{
Assert.Empty(db.Players);
Assert.Single(db.AppState);
});
}
}