test(domain): approve use case sets the zaak status via the ACL, idempotently (refs #75)

Red: ApproveRegistration and IAclClient.ApproveZaakAsync don't exist yet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-13 16:50:45 +02:00
parent ca9964f79b
commit 66fe1e5f6f
2 changed files with 84 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
using Big.Application;
using Big.Domain;
namespace Big.Tests;
public class ApproveRegistrationTests
{
private static Registration WithZaak(string bsn = "123456782")
{
var registration = Registration.Submit(bsn);
registration.AttachZaak(FakeAclClient.DefaultZaakUrl);
return registration;
}
[Fact]
public async Task Approving_sets_the_zaak_status_via_the_acl_and_marks_the_registration_ingeschreven()
{
var store = new FakeRegistrationStore();
var acl = new FakeAclClient();
var registration = WithZaak();
store.Seed(registration);
var handler = new ApproveRegistration(store, acl);
await handler.HandleAsync(new ApproveRegistrationCommand(registration.Id));
var saved = await store.GetAsync(registration.Id);
Assert.Equal(RegistrationStatus.Ingeschreven, saved!.Status);
Assert.Equal(FakeAclClient.DefaultZaakUrl, acl.ApprovedZaakUrl);
Assert.Equal(1, acl.ApproveCallCount);
}
[Fact]
public async Task Approving_an_unknown_registration_throws_and_does_not_call_the_acl()
{
var store = new FakeRegistrationStore();
var acl = new FakeAclClient();
var handler = new ApproveRegistration(store, acl);
await Assert.ThrowsAsync<InvalidOperationException>(
() => handler.HandleAsync(new ApproveRegistrationCommand(RegistrationId.New())));
Assert.Equal(0, acl.ApproveCallCount);
}
[Fact]
public async Task Approving_before_the_zaak_is_opened_throws_without_calling_the_acl()
{
var store = new FakeRegistrationStore();
var acl = new FakeAclClient();
var registration = Registration.Submit("123456782"); // no zaak yet
store.Seed(registration);
var handler = new ApproveRegistration(store, acl);
await Assert.ThrowsAsync<InvalidOperationException>(
() => handler.HandleAsync(new ApproveRegistrationCommand(registration.Id)));
Assert.Equal(0, acl.ApproveCallCount);
}
[Fact]
public async Task Re_approving_an_already_ingeschreven_registration_is_idempotent()
{
var store = new FakeRegistrationStore();
var acl = new FakeAclClient();
var registration = WithZaak();
store.Seed(registration);
var handler = new ApproveRegistration(store, acl);
await handler.HandleAsync(new ApproveRegistrationCommand(registration.Id));
await handler.HandleAsync(new ApproveRegistrationCommand(registration.Id));
// The second approval is a no-op: the ACL is not asked to set the status again.
Assert.Equal(1, acl.ApproveCallCount);
Assert.Equal(RegistrationStatus.Ingeschreven, (await store.GetAsync(registration.Id))!.Status);
}
}

View File

@@ -52,10 +52,20 @@ internal sealed class FakeAclClient(Uri? zaakUrl = null) : IAclClient
public string? OpenedForBsn { get; private set; }
public int CallCount { get; private set; }
public Uri? ApprovedZaakUrl { get; private set; }
public int ApproveCallCount { get; private set; }
public Task<Uri> OpenZaakAsync(string bsn, CancellationToken ct = default)
{
CallCount++;
OpenedForBsn = bsn;
return Task.FromResult(_zaakUrl);
}
public Task ApproveZaakAsync(Uri zaakUrl, CancellationToken ct = default)
{
ApproveCallCount++;
ApprovedZaakUrl = zaakUrl;
return Task.CompletedTask;
}
}