From 79dcd8f14bea09b507337e2af427be48d32a2ead Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Tue, 30 Jun 2026 17:15:23 +0200 Subject: [PATCH] test(domain): acceptance scenario for submitting a registration (refs #6) Use-case-level BDD (Reqnroll) for S-05: a zorgprofessional submits a registration; the Domain Service starts the registratie process and the OpenZaakAanmaken external task opens a zaak via the ACL, recorded on the aggregate (ADR-0009). Driven against in-memory Workflow Client and ACL stand-ins; real Flowable+ACL+OpenZaak delivery is the live-stack verify-domain check. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/acceptance/Acceptance.csproj | 1 + .../Features/RegistratieIndienen.feature | 18 +++++++ .../Steps/RegistratieIndienenSteps.cs | 54 +++++++++++++++++++ .../acceptance/Support/InMemoryDomainPorts.cs | 50 +++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 tests/acceptance/Features/RegistratieIndienen.feature create mode 100644 tests/acceptance/Steps/RegistratieIndienenSteps.cs create mode 100644 tests/acceptance/Support/InMemoryDomainPorts.cs diff --git a/tests/acceptance/Acceptance.csproj b/tests/acceptance/Acceptance.csproj index 7b795eb..08d182b 100644 --- a/tests/acceptance/Acceptance.csproj +++ b/tests/acceptance/Acceptance.csproj @@ -19,6 +19,7 @@ + diff --git a/tests/acceptance/Features/RegistratieIndienen.feature b/tests/acceptance/Features/RegistratieIndienen.feature new file mode 100644 index 0000000..1f78c95 --- /dev/null +++ b/tests/acceptance/Features/RegistratieIndienen.feature @@ -0,0 +1,18 @@ +# language: en +# Drives S-05 (#6). A zorgprofessional submits a registration; the Domain Service starts the +# registratie process and, via the external-task worker, opens a zaak through the ACL and records +# it on the aggregate (ADR-0009). This scenario exercises the use cases against in-memory stand-ins +# for the Workflow Client and the ACL; real Flowable + ACL + OpenZaak delivery is verified by the +# live-stack check (verify-domain). +Feature: Een registratie indienen + Als zorgprofessional wil ik mijn registratie indienen + zodat er een registratieproces start en een zaak wordt geopend. + + Scenario: Indienen start het registratieproces en opent een zaak + Given a zorgprofessional submits a registration for BSN "123456782" + When the domain service handles the submission + Then a registratie process is started for the registration + And the registration has status "INGEDIEND" + When the OpenZaakAanmaken external task is handled for the registration + Then a zaak is opened via the ACL for BSN "123456782" + And the zaak is recorded on the registration diff --git a/tests/acceptance/Steps/RegistratieIndienenSteps.cs b/tests/acceptance/Steps/RegistratieIndienenSteps.cs new file mode 100644 index 0000000..a882e9e --- /dev/null +++ b/tests/acceptance/Steps/RegistratieIndienenSteps.cs @@ -0,0 +1,54 @@ +using Acceptance.Support; +using Big.Application; +using Big.Domain; +using Reqnroll; +using Xunit; + +namespace Acceptance.Steps; + +/// Bindings for RegistratieIndienen.feature (S-05). Drives the SubmitRegistration +/// and OpenZaakWorker use cases against in-memory ports; one instance per scenario. +[Binding] +public sealed class RegistratieIndienenSteps +{ + private readonly InMemoryWorkflowClient _workflow = new(); + private readonly InMemoryAclClient _acl = new(); + private readonly InMemoryRegistrationStore _store = new(); + private string _bsn = ""; + private RegistrationId _id; + + [Given("a zorgprofessional submits a registration for BSN \"(.*)\"")] + public void GivenAZorgprofessionalSubmitsARegistration(string bsn) => _bsn = bsn; + + [When("the domain service handles the submission")] + public async Task WhenTheDomainServiceHandlesTheSubmission() + => _id = await new SubmitRegistration(_store, _workflow).HandleAsync(new SubmitRegistrationCommand(_bsn)); + + [Then("a registratie process is started for the registration")] + public void ThenARegistratieProcessIsStarted() + => Assert.Equal(_id, _workflow.StartedFor); + + [Then("the registration has status \"(.*)\"")] + public async Task ThenTheRegistrationHasStatus(string expected) + { + var registration = await _store.GetAsync(_id); + Assert.NotNull(registration); + Assert.Equal(expected, registration.Status.ToString().ToUpperInvariant()); + Assert.Equal(InMemoryWorkflowClient.StartedProcessInstanceId, registration.ProcessInstanceId); + } + + [When("the OpenZaakAanmaken external task is handled for the registration")] + public async Task WhenTheExternalTaskIsHandled() + => await new OpenZaakWorker(_store, _acl).HandleAsync(new OpenZaakJob("job-acc-1", _id)); + + [Then("a zaak is opened via the ACL for BSN \"(.*)\"")] + public void ThenAZaakIsOpenedViaTheAcl(string bsn) + => Assert.Equal(bsn, _acl.OpenedForBsn); + + [Then("the zaak is recorded on the registration")] + public async Task ThenTheZaakIsRecordedOnTheRegistration() + { + var registration = await _store.GetAsync(_id); + Assert.Equal(InMemoryAclClient.OpenedZaakUrl, registration!.ZaakUrl); + } +} diff --git a/tests/acceptance/Support/InMemoryDomainPorts.cs b/tests/acceptance/Support/InMemoryDomainPorts.cs new file mode 100644 index 0000000..3059aa7 --- /dev/null +++ b/tests/acceptance/Support/InMemoryDomainPorts.cs @@ -0,0 +1,50 @@ +using Big.Application; +using Big.Domain; + +namespace Acceptance.Support; + +/// An in-memory Workflow Client for the domain acceptance scenario: it records which +/// registration a process was started for and returns a fixed instance id. The acceptance test +/// drives the use case without a running Flowable (live verification is the verify-domain check). +public sealed class InMemoryWorkflowClient : IWorkflowClient +{ + public const string StartedProcessInstanceId = "proc-acc-1"; + + public RegistrationId? StartedFor { get; private set; } + + public Task StartRegistrationProcessAsync(RegistrationId registrationId, CancellationToken ct = default) + { + StartedFor = registrationId; + return Task.FromResult(StartedProcessInstanceId); + } +} + +/// An in-memory ACL stand-in: records the bsn it opened a zaak for and returns a fixed URL, +/// so the scenario verifies the domain crosses the ACL boundary (ยง8.1) without a running OpenZaak. +public sealed class InMemoryAclClient : IAclClient +{ + public static readonly Uri OpenedZaakUrl = new("http://openzaak/zaken/api/v1/zaken/acc-zaak"); + + public string? OpenedForBsn { get; private set; } + + public Task OpenZaakAsync(string bsn, CancellationToken ct = default) + { + OpenedForBsn = bsn; + return Task.FromResult(OpenedZaakUrl); + } +} + +/// An in-memory registration store for the domain acceptance scenario. +public sealed class InMemoryRegistrationStore : IRegistrationStore +{ + private readonly Dictionary _byId = []; + + public Task SaveAsync(Registration registration, CancellationToken ct = default) + { + _byId[registration.Id] = registration; + return Task.CompletedTask; + } + + public Task GetAsync(RegistrationId id, CancellationToken ct = default) + => Task.FromResult(_byId.GetValueOrDefault(id)); +}