Drive herregistratie as a state-machine wizard
Model the multi-step form as one tagged union: step/errors exist only while Editing, and Submitting/Submitted/Failed carry a parsed Valid payload. So "submitting while a field is invalid" and "success screen with errors set" are unrepresentable by construction. Pure transitions (next/back/submit/resolve) with a spec covering the key invariants; illegal events are no-ops. The page becomes pure composition. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ok, err } from '../../core/fp';
|
||||
import { initial, next, back, submit, resolve, WizardState } from './wizard.machine';
|
||||
|
||||
const editing1 = (uren: string, punten = ''): WizardState => ({ tag: 'Editing', step: 1, draft: { uren, punten }, errors: {} });
|
||||
const editing2 = (uren: string, punten: string): WizardState => ({ tag: 'Editing', step: 2, draft: { uren, punten }, errors: {} });
|
||||
|
||||
describe('wizard.machine', () => {
|
||||
it('next advances only when step 1 parses', () => {
|
||||
expect(next(initial).tag).toBe('Editing'); // empty uren -> stays, with error
|
||||
expect((next(initial) as any).errors.uren).toBeTruthy();
|
||||
expect((next(editing1('4160')) as any).step).toBe(2);
|
||||
});
|
||||
|
||||
it('submit reaches Submitting ONLY with fully valid data', () => {
|
||||
expect(submit(editing2('4160', 'x')).tag).toBe('Editing'); // invalid punten -> no Submitting
|
||||
const good = submit(editing2('4160', '200'));
|
||||
expect(good.tag).toBe('Submitting');
|
||||
expect((good as any).data).toEqual({ uren: 4160, punten: 200 });
|
||||
});
|
||||
|
||||
it('back / resolve are no-ops from illegal states', () => {
|
||||
expect(back(initial)).toBe(initial); // step 1, nothing to go back to
|
||||
expect(resolve(initial, ok(undefined))).toBe(initial); // not Submitting
|
||||
});
|
||||
|
||||
it('resolve maps Submitting to Submitted / Failed', () => {
|
||||
const submitting = submit(editing2('4160', '200'));
|
||||
expect(resolve(submitting, ok(undefined)).tag).toBe('Submitted');
|
||||
expect(resolve(submitting, err('boom')).tag).toBe('Failed');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user