Files
atomic-design-poc/backend/tests/BigRegister.Tests/StamdataEndpointTests.cs
T
ehoandClaude Opus 5 2627799284 fix(backend): 400 instead of 500 on an unparseable peildatum (RB-16)
BIO-019: GET /stamdata/{table}?peildatum= called DateOnly.Parse
directly, which throws FormatException on anything unparseable — an
unhandled 500 (leaking exception detail in Development) instead of
the 400-with-problem-details every other bad-input check in this file
returns. §3c named backend/Stamdata's 71.7% branch coverage (BL-005)
as the weak spot this bug lived in.

Switched to DateOnly.TryParse; an unparseable value now returns
Results.Problem(detail: ..., statusCode: 400), matching the shape the
upload/change-request endpoints already use. Endpoint doc gained
.ProducesProblem(400), so the OpenAPI doc + generated client were
regenerated and committed in this same diff (RB-09's note records a
prior incident where a response-shape change shipped without this and
the drift went unnoticed).

No FE change needed: libs/beheer's stamdata adapter already funnels
every call through runSubmit, which folds any thrown ApiException
(now including this 400) into a generic Result error — ADR-0001's
"the FE renders the decision" already covers "the server rejected
this input".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 16:53:29 +02:00

79 lines
3.1 KiB
C#

using System.Net;
using System.Net.Http.Json;
using BigRegister.Api.Contracts;
using Microsoft.AspNetCore.Mvc.Testing;
namespace BigRegister.Tests;
/// <summary>
/// The stamdata maintenance reads (ADR-0004): admin-only, generic (schema + rows), and the
/// valid-time peildatum filter. The editor consumes these; the edit itself lands as a PR.
/// </summary>
public class StamdataEndpointTests(TestWebApplicationFactory factory) : IClassFixture<TestWebApplicationFactory>
{
private readonly HttpClient _client = factory.CreateClient();
private HttpRequestMessage Req(HttpMethod method, string path, string? role = null)
{
var req = new HttpRequestMessage(method, path);
if (role is not null) req.Headers.Add("X-Role", role);
return req;
}
[Fact]
public async Task Stamdata_reads_are_admin_only()
{
Assert.Equal(HttpStatusCode.Forbidden, (await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata"))).StatusCode);
Assert.Equal(HttpStatusCode.Forbidden, (await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions", role: "drafter"))).StatusCode);
}
[Fact]
public async Task Table_list_exposes_the_reflected_schema()
{
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata", role: "admin"));
res.EnsureSuccessStatusCode();
var tables = (await res.Content.ReadFromJsonAsync<List<StamdataTableSummaryDto>>())!;
var professions = tables.Single(t => t.Id == "professions");
Assert.True(professions.Temporal);
Assert.True(professions.Columns[0].IsKey);
Assert.Equal("program", professions.Columns[0].Name);
Assert.Contains(professions.Columns, c => c.Name == "geldigVan" && c.Type == "date");
}
[Fact]
public async Task Table_returns_all_rows_without_a_peildatum()
{
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions", role: "admin"));
res.EnsureSuccessStatusCode();
var table = (await res.Content.ReadFromJsonAsync<StamdataTableDto>())!;
Assert.Equal(5, table.Rows.Count);
}
[Fact]
public async Task Peildatum_before_the_seed_windows_hides_every_row()
{
// Seed mappings start 2000-01-01; a 1999 peildatum yields none (valid-time filter works).
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions?peildatum=1999-01-01", role: "admin"));
res.EnsureSuccessStatusCode();
var table = (await res.Content.ReadFromJsonAsync<StamdataTableDto>())!;
Assert.Empty(table.Rows);
}
/// RB-16/BIO-019: DateOnly.Parse used to throw FormatException on unparseable input,
/// surfacing as an unhandled 500 instead of the 400-with-problem-details every other
/// bad-input check in this endpoint file returns.
[Fact]
public async Task Unparseable_peildatum_is_400_not_500()
{
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/professions?peildatum=not-a-date", role: "admin"));
Assert.Equal(HttpStatusCode.BadRequest, res.StatusCode);
}
[Fact]
public async Task Unknown_table_is_404()
{
var res = await _client.SendAsync(Req(HttpMethod.Get, "/api/v1/stamdata/nope", role: "admin"));
Assert.Equal(HttpStatusCode.NotFound, res.StatusCode);
}
}