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'); }); });