Files
register-referentie/tests/acceptance/Steps/BffToegangSteps.cs
Niek Otten 9997da8beb
All checks were successful
CI / lint (push) Successful in 1m25s
CI / build (push) Successful in 1m17s
CI / unit (push) Successful in 1m33s
CI / frontend (push) Successful in 2m54s
CI / mutation (push) Successful in 6m34s
CI / verify-stack (push) Successful in 7m39s
feat(#78): one citizen reference across self-service and the openbaar register (#79)
## What & why

Before this change the self-service confirmation and the openbaar register showed **different** identifiers, so a citizen could not look their registration back up (#78). Now both surface the same **reference**:

- **domain → ACL (write):** the domain `registrationId` is set as the zaak's `identificatie` on `POST /zaken`.
- **event-subscriber → ACL (read):** the subscriber reads the zaak's `identificatie` back through the ACL (§8.1 — only the ACL talks to ZGW) via a new `POST /zaken/reference`, and stores it on the projection row **and** the `processed_notifications` replay log.
- **BFF + openbaar:** the public view exposes `id/status/reference` (never bsn/naam) and searches by id or reference; the register's "Referentie" column shows the reference.

Storing the reference in the replay log keeps ADR-0008's **rebuild-is-log-only** invariant intact — `/admin/rebuild` reproduces the reference without re-reading the ACL.

Decision recorded in **ADR-0012**.

## Definition of Done

- [x] Linked issue: #78
- [x] Tests written first; red → green per layer
- [x] Unit + acceptance green (`make unit`): domain 49, acl 27, bff 20, event-subscriber 19, acceptance 7
- [x] Frontend lint + test green (`nx run-many -t lint test`)
- [x] Mutation ≥ break(90): acl 100%, event-subscriber 100%, bff 100%, domain 98.41% (pre-existing FlowableWorkflowClient baseline, untouched)
- [x] e2e extended: confirmation reference == register reference
- [x] openapi.json + api-client regenerated (drift guard green)
- [x] ADR-0012 added; demo-script note appended
- [x] `Acl__BaseUrl` wired for the subscriber in compose

closes #78

Reviewed-on: #79
2026-07-14 14:01:49 +00:00

84 lines
2.8 KiB
C#

using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using Acceptance.Support;
using Bff.Api;
using Reqnroll;
using Xunit;
namespace Acceptance.Steps;
/// <summary>Bindings for <c>BffToegang.feature</c> (S-07). Drives the real BFF over HTTP with a
/// fake domain + projection and locally-minted tokens (ADR-0010). One host per scenario.</summary>
[Binding]
public sealed class BffToegangSteps : IDisposable
{
private readonly BffAcceptanceHost _host = new();
private HttpClient _client = null!;
private string? _token;
private HttpResponseMessage? _response;
[Given("a zorgprofessional with a valid DigiD token for BSN \"(.*)\"")]
public void GivenAValidToken(string bsn)
{
_token = BffAcceptanceHost.MintToken(bsn);
_client = _host.CreateClient();
}
[Given("a caller without a token")]
public void GivenNoToken() => _client = _host.CreateClient();
[Given("the projection contains a zaak \"(.*)\" for BSN \"(.*)\"")]
public void GivenTheProjectionContains(string zaakId, string bsn)
{
_host.Projection.Entries.Add(new ProjectionEntry(zaakId, "INGEDIEND", "REG-" + zaakId, bsn, null));
_client = _host.CreateClient();
}
[When("they submit a registration via the BFF")]
public async Task WhenTheySubmit()
{
var request = new HttpRequestMessage(HttpMethod.Post, "/self-service/registrations")
{
Content = JsonContent.Create(new { }),
};
if (_token is not null)
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
_response = await _client.SendAsync(request);
}
[When("the openbaar register is queried anonymously")]
public async Task WhenTheOpenbaarRegisterIsQueried()
=> _response = await _client.GetAsync("/openbaar/register");
[Then("the BFF accepts it and forwards BSN \"(.*)\" to the domain")]
public void ThenAcceptedAndForwarded(string bsn)
{
Assert.Equal(HttpStatusCode.Accepted, _response!.StatusCode);
Assert.Equal(bsn, _host.Domain.SubmittedBsn);
}
[Then("the BFF rejects it as unauthorized")]
public void ThenUnauthorized()
{
Assert.Equal(HttpStatusCode.Unauthorized, _response!.StatusCode);
Assert.Null(_host.Domain.SubmittedBsn);
}
[Then("the response lists \"(.*)\" without exposing the BSN")]
public async Task ThenListsWithoutBsn(string zaakId)
{
Assert.Equal(HttpStatusCode.OK, _response!.StatusCode);
var body = await _response.Content.ReadAsStringAsync();
Assert.Contains(zaakId, body);
Assert.DoesNotContain("123456782", body);
}
public void Dispose()
{
_response?.Dispose();
_client?.Dispose();
_host.Dispose();
}
}