docs(test): make Given/When/Then the default BDD structure (WP-71)

bdd.mdx previously banned "Given/When/Then ceremony" outright, which
directly contradicted WP-70's own acceptance tests (Acceptance/
BesluitLifecycleTests.cs already used // Given/When/Then comments) and
the backend's organically-evolved PascalCase_snake_sentence convention,
which the doc gave zero guidance for. Reverses that rule: every test is
now structured Given -> When -> Then, with a genuinely empty phase
omitted rather than faked; present-tense declarative naming and the
one-behaviour-per-test rule are unchanged. ADR-0006 gets a cross-reference
so both documents agree everywhere, not just in acceptance tests.

Also closes out the doc's other named-but-unenforced rules found by the
audit: fixes the 5 files asserting rendered $localize copy instead of
the underlying tag/message-id (the compliant pattern already existed in
werkvoorraad-item-view.spec.ts), splits the multi-behaviour titles the
doc itself calls a smell (";", "and", "/"), and fixes bdd.mdx's own false
citation of registratie-wizard.machine.spec.ts as "one transition per
test" by actually splitting that test into one-transition-per-test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-08-18 20:25:30 +02:00
co-authored by Claude Sonnet 5
parent 306d002221
commit 3652ff8d3f
9 changed files with 247 additions and 34 deletions
@@ -77,15 +77,20 @@ describe('intake acceptance journeys', () => {
});
});
it('buitenland gewerkt requires land + hours abroad, and gaNaarStap corrects an earlier answer', () => {
it('buitenland gewerkt requires land and hours abroad before advancing', () => {
// Given a user who says they worked abroad.
// When they try to advance without a country...
const blocked = givenIntake(
{ tag: 'SetAnswer', key: 'buitenlandGewerkt', value: 'ja' },
{ tag: 'Next' },
);
// Then they stay on the same step, blocked by a missing 'land' answer.
expect(blocked.tag).toBe('Answering');
expect(blocked.tag === 'Answering' && blocked.cursor).toBe(0);
expect(blocked.tag === 'Answering' && blocked.errors.land).toBeTruthy();
// When land and hours abroad are supplied, and the rest of the journey answered...
const reviewing = given(reduce, blocked)(
{ tag: 'SetAnswer', key: 'land', value: 'Duitsland' },
{ tag: 'SetAnswer', key: 'buitenlandseUren', value: '300' },
@@ -93,16 +98,34 @@ describe('intake acceptance journeys', () => {
{ tag: 'SetAnswer', key: 'uren', value: '1200' },
{ tag: 'Next' }, // werk step valid, uren high enough to skip scholing -> review
);
// Then the journey advances all the way to review.
expect(reviewing.tag).toBe('Answering');
expect(reviewing.tag === 'Answering' && reviewing.cursor).toBe(2); // review
});
// Jump back from review to correct the country, without losing later answers.
it('gaNaarStap corrects an earlier answer without losing later ones', () => {
// Given a journey that reached review with a foreign-work answer.
const reviewing = givenIntake(
{ tag: 'SetAnswer', key: 'buitenlandGewerkt', value: 'ja' },
{ tag: 'Next' },
{ tag: 'SetAnswer', key: 'land', value: 'Duitsland' },
{ tag: 'SetAnswer', key: 'buitenlandseUren', value: '300' },
{ tag: 'Next' },
{ tag: 'SetAnswer', key: 'uren', value: '1200' },
{ tag: 'Next' },
);
// When gaNaarStap jumps back to correct the country...
const corrected: IntakeState = given(reduce, reviewing)(
{ tag: 'GaNaarStap', cursor: 0 },
{ tag: 'SetAnswer', key: 'land', value: 'België' },
{ tag: 'Next' }, // buitenland step re-validated
{ tag: 'Next' }, // werk step re-validated (earlier 'uren' answer preserved)
);
// Then the correction lands back on review with the new answer, and the later
// 'uren' answer is preserved rather than lost.
expect(corrected.tag).toBe('Answering');
expect(corrected.tag === 'Answering' && corrected.cursor).toBe(2);
expect(corrected.tag === 'Answering' && corrected.answers.land).toBe('België');
@@ -111,6 +134,7 @@ describe('intake acceptance journeys', () => {
const noForwardJump = reduce(corrected, { tag: 'GaNaarStap', cursor: 2 });
expect(noForwardJump).toBe(corrected);
// And the corrected journey still submits successfully with the corrected data.
const done = given(reduce, corrected)({ tag: 'Submit' }, { tag: 'SubmitConfirmed' });
expect(done.tag).toBe('Submitted');
expect(done.tag === 'Submitted' && done.data).toEqual({