test: close illegal-state escape hatches in spec type-safety (WP-71)
ESLint blanket-exempted every *.spec.ts from the any ban, and no gate type-checked spec files at all (ng test is transpile-only), so a wrong cast in a test could never fail the build. 76 `as any` + 12 `as Extract<>` state-narrowing casts in the three biggest wizard specs read one variant's fields off a whole-union value: if the reducer returned the wrong variant, the assertion silently read undefined instead of failing. expectTag(state, tag) (libs/shared/src/testing/expect-tag.ts) asserts and narrows in one call, replacing every one of those casts. Removes the spec-file any exemption, adds `npm run typecheck` (tsc --noEmit over each project's tsconfig.spec.json) to CI, and forbids production code from importing libs/shared/src/testing via dependency-cruiser. Backend: AanvraagBuilder now models ZaakUrl (closing the last post-Build() mutation) and guards AtStep; null-forgiving `!` on endpoint assertions replaced with Assert.NotNull so a null DTO fails by name, not NullReferenceException. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,11 +15,15 @@ public class ApplicationTests(TestWebApplicationFactory factory) : IClassFixture
|
||||
{
|
||||
// WP-35: one Concept per type is now server-enforced, and these tests share one DB
|
||||
// (IClassFixture). Clear any leftover Concept so each test starts from a clean slate.
|
||||
foreach (var s in (await List())!.Where(x => x.Status.Tag == "Concept"))
|
||||
var existing = await List();
|
||||
Assert.NotNull(existing);
|
||||
foreach (var s in existing.Where(x => x.Status.Tag == "Concept"))
|
||||
await _client.DeleteAsync($"/api/v1/applications/{s.Id}");
|
||||
var res = await _client.PostAsJsonAsync("/api/v1/applications", new { type });
|
||||
Assert.Equal(HttpStatusCode.Created, res.StatusCode);
|
||||
return (await res.Content.ReadFromJsonAsync<ApplicationDetailDto>())!;
|
||||
var created = await res.Content.ReadFromJsonAsync<ApplicationDetailDto>();
|
||||
Assert.NotNull(created);
|
||||
return created;
|
||||
}
|
||||
|
||||
private Task<List<ApplicationSummaryDto>?> List() =>
|
||||
@@ -34,7 +38,9 @@ public class ApplicationTests(TestWebApplicationFactory factory) : IClassFixture
|
||||
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);
|
||||
var list = await List();
|
||||
Assert.NotNull(list);
|
||||
var mine = 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);
|
||||
@@ -48,8 +54,9 @@ public class ApplicationTests(TestWebApplicationFactory factory) : IClassFixture
|
||||
new { draft = new { beroep = "verpleegkundige" }, stepIndex = 2, stepCount = 4 });
|
||||
|
||||
var detail = await _client.GetFromJsonAsync<ApplicationDetailDto>($"/api/v1/applications/{a.Id}");
|
||||
Assert.NotNull(detail!.Draft);
|
||||
Assert.Equal("verpleegkundige", detail.Draft!.Value.GetProperty("beroep").GetString());
|
||||
Assert.NotNull(detail);
|
||||
Assert.NotNull(detail.Draft);
|
||||
Assert.Equal("verpleegkundige", detail.Draft.Value.GetProperty("beroep").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -237,7 +244,8 @@ public class ApplicationTests(TestWebApplicationFactory factory) : IClassFixture
|
||||
public void AutoApprovable_flips_to_goedgekeurd_after_the_window()
|
||||
{
|
||||
var a = Accepted(autoApprovable: true);
|
||||
var t0 = a.SubmittedAt!.Value;
|
||||
Assert.NotNull(a.SubmittedAt);
|
||||
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);
|
||||
}
|
||||
@@ -246,20 +254,10 @@ public class ApplicationTests(TestWebApplicationFactory factory) : IClassFixture
|
||||
public void Manual_case_never_auto_advances()
|
||||
{
|
||||
var a = Accepted(autoApprovable: false);
|
||||
var far = a.SubmittedAt!.Value + ApplicationStore.ProcessingWindow + TimeSpan.FromDays(1);
|
||||
Assert.NotNull(a.SubmittedAt);
|
||||
var far = a.SubmittedAt.Value + ApplicationStore.ProcessingWindow + TimeSpan.FromDays(1);
|
||||
var status = a.ToStatusDto(far);
|
||||
Assert.Equal("InBehandeling", status.Tag);
|
||||
Assert.True(status.Manual);
|
||||
}
|
||||
|
||||
// WP-63: the published lifecycle (ADR-0002) must name exactly these five tags, in this
|
||||
// order — ToStatusDto's string literals must keep matching Enum.ToString(), and Ingediend/
|
||||
// MeerInfoGevraagd (unreachable until WP-65 adds the behandelaar transition) stay defined.
|
||||
[Fact]
|
||||
public void AanvraagStatusTag_covers_the_published_lifecycle()
|
||||
{
|
||||
Assert.Equal(
|
||||
new[] { "Ingediend", "InBehandeling", "MeerInfoGevraagd", "Goedgekeurd", "Afgewezen" },
|
||||
Enum.GetNames<AanvraagStatusTag>());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user