using System.Net; using System.Net.Http.Json; using BigRegister.Api.Contracts; using BigRegister.Api.Data; using Microsoft.AspNetCore.Mvc.Testing; namespace BigRegister.Tests; public class ApplicationTests(WebApplicationFactory factory) : IClassFixture> { private readonly HttpClient _client = factory.CreateClient(); private async Task Create(string type = "registratie") { var res = await _client.PostAsJsonAsync("/api/v1/applications", new { type }); Assert.Equal(HttpStatusCode.Created, res.StatusCode); return (await res.Content.ReadFromJsonAsync())!; } private Task?> List() => _client.GetFromJsonAsync>("/api/v1/applications"); // --- Lifecycle over HTTP --- [Fact] public async Task Create_then_list_shows_a_concept_with_step_progress() { var a = await Create(); await _client.PutAsJsonAsync($"/api/v1/applications/{a.Id}", new { draft = new { beroep = "arts" }, stepIndex = 1, stepCount = 4 }); var mine = (await List())!.Single(x => x.Id == a.Id); Assert.Equal("Concept", mine.Status.Tag); Assert.Equal(1, mine.Status.StepIndex); Assert.Equal(4, mine.Status.StepCount); } [Fact] public async Task Draft_sync_is_readable_back_from_detail() { var a = await Create(); await _client.PutAsJsonAsync($"/api/v1/applications/{a.Id}", new { draft = new { beroep = "verpleegkundige" }, stepIndex = 2, stepCount = 4 }); var detail = await _client.GetFromJsonAsync($"/api/v1/applications/{a.Id}"); Assert.NotNull(detail!.Draft); Assert.Equal("verpleegkundige", detail.Draft!.Value.GetProperty("beroep").GetString()); } [Fact] public async Task Submit_duo_registratie_is_in_behandeling_and_auto() { var a = await Create("registratie"); var res = await _client.PostAsJsonAsync($"/api/v1/applications/{a.Id}/submit", new { diplomaHerkomst = "duo" }); res.EnsureSuccessStatusCode(); var body = (await res.Content.ReadFromJsonAsync())!; Assert.StartsWith("BIG-2026-", body.Referentie); Assert.Equal("InBehandeling", body.Status.Tag); Assert.False(body.Status.Manual); // auto-approvable → not a manual case } [Fact] public async Task Submit_handmatig_registratie_succeeds_as_manual_case() { var a = await Create("registratie"); var res = await _client.PostAsJsonAsync($"/api/v1/applications/{a.Id}/submit", new { diplomaHerkomst = "handmatig" }); res.EnsureSuccessStatusCode(); // no longer a 422 var body = (await res.Content.ReadFromJsonAsync())!; Assert.Equal("InBehandeling", body.Status.Tag); Assert.True(body.Status.Manual); } [Fact] public async Task Submit_herregistratie_with_zero_uren_is_afgewezen() { var a = await Create("herregistratie"); var res = await _client.PostAsJsonAsync($"/api/v1/applications/{a.Id}/submit", new { uren = 0 }); res.EnsureSuccessStatusCode(); // the submission is accepted... var body = (await res.Content.ReadFromJsonAsync())!; Assert.Equal("Afgewezen", body.Status.Tag); // ...but resolves to rejected Assert.NotNull(body.Status.Reden); } [Fact] public async Task Submitting_twice_conflicts() { var a = await Create("registratie"); (await _client.PostAsJsonAsync($"/api/v1/applications/{a.Id}/submit", new { diplomaHerkomst = "duo" })).EnsureSuccessStatusCode(); var again = await _client.PostAsJsonAsync($"/api/v1/applications/{a.Id}/submit", new { diplomaHerkomst = "duo" }); Assert.Equal(HttpStatusCode.Conflict, again.StatusCode); } [Fact] public async Task Cancel_concept_removes_it() { var a = await Create(); Assert.Equal(HttpStatusCode.NoContent, (await _client.DeleteAsync($"/api/v1/applications/{a.Id}")).StatusCode); Assert.Equal(HttpStatusCode.NotFound, (await _client.GetAsync($"/api/v1/applications/{a.Id}")).StatusCode); } [Fact] public async Task Cancel_submitted_aanvraag_conflicts() { var a = await Create("registratie"); (await _client.PostAsJsonAsync($"/api/v1/applications/{a.Id}/submit", new { diplomaHerkomst = "duo" })).EnsureSuccessStatusCode(); Assert.Equal(HttpStatusCode.Conflict, (await _client.DeleteAsync($"/api/v1/applications/{a.Id}")).StatusCode); } // --- Auto-approval is computed on read: exercise the window boundary without waiting. --- private static Aanvraag Accepted(bool autoApprovable) => new() { Id = "x", Type = "registratie", Owner = "test", Submitted = true, AutoApprovable = autoApprovable, Referentie = "BIG-2026-1", SubmittedAt = DateTimeOffset.UtcNow, CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow, }; [Fact] public void AutoApprovable_flips_to_goedgekeurd_after_the_window() { var a = Accepted(autoApprovable: true); var t0 = a.SubmittedAt!.Value; Assert.Equal("InBehandeling", a.ToStatusDto(t0 + ApplicationStore.ProcessingWindow - TimeSpan.FromSeconds(1)).Tag); Assert.Equal("Goedgekeurd", a.ToStatusDto(t0 + ApplicationStore.ProcessingWindow + TimeSpan.FromSeconds(1)).Tag); } [Fact] public void Manual_case_never_auto_advances() { var a = Accepted(autoApprovable: false); var far = a.SubmittedAt!.Value + ApplicationStore.ProcessingWindow + TimeSpan.FromDays(1); var status = a.ToStatusDto(far); Assert.Equal("InBehandeling", status.Tag); Assert.True(status.Manual); } }