import { describe, expect, it } from 'vitest' import { formatFieldValue } from '@form-schema/composables/formatFieldValue' import { FormFieldType } from '@form-schema/types/formBuilder' import type { AvailableTag, PublicFormField, PublicFormSectionOption, PublicFormTimeSlot, } from '@form-schema/types/formBuilder' function field(partial: Partial = {}): PublicFormField { return { id: partial.id ?? 'f', slug: partial.slug ?? 'slug', field_type: partial.field_type ?? FormFieldType.TEXT, label: partial.label ?? 'Label', help_text: partial.help_text ?? null, options: partial.options ?? null, available_tags: partial.available_tags ?? null, validation_rules: partial.validation_rules ?? null, is_required: partial.is_required ?? false, display_width: partial.display_width ?? 'full', conditional_logic: partial.conditional_logic ?? null, sort_order: partial.sort_order ?? 0, form_schema_section_id: partial.form_schema_section_id ?? null, } } function tag(partial: Partial): AvailableTag { return { id: partial.id ?? 't_1', name: partial.name ?? 'Tag', category: partial.category ?? '' } } function timeSlot(partial: Partial): PublicFormTimeSlot { return { id: partial.id ?? 'ts_1', name: partial.name ?? 'Vrijdag avond', date: partial.date ?? '2026-07-10', start_time: partial.start_time ?? '18:00:00', end_time: partial.end_time ?? '23:00:00', duration_hours: partial.duration_hours ?? 5, event_id: partial.event_id ?? 'evt_1', event_name: partial.event_name ?? 'Event', } } function section(partial: Partial): PublicFormSectionOption { return { id: partial.id ?? 's_1', name: partial.name ?? 'Section', category: partial.category ?? null, icon: partial.icon ?? null, registration_description: partial.registration_description ?? null, } } describe('formatFieldValue', () => { describe('empty values', () => { it.each<[unknown]>([ [null], [undefined], [''], [[]], ])('returns "—" for empty value %s on any field type', v => { expect(formatFieldValue(field({ field_type: FormFieldType.TEXT }), v, [], [])).toBe('—') }) }) describe('TAG_PICKER', () => { it('maps IDs to tag names using field.available_tags', () => { const f = field({ field_type: FormFieldType.TAG_PICKER, available_tags: [tag({ id: 'a', name: 'Tapper' }), tag({ id: 'b', name: 'Barista' })], }) expect(formatFieldValue(f, ['a', 'b'], undefined, undefined)).toBe('Tapper, Barista') }) it('labels unknown tag IDs as "(onbekende tag)"', () => { const f = field({ field_type: FormFieldType.TAG_PICKER, available_tags: [tag({ id: 'a', name: 'Tapper' })], }) expect(formatFieldValue(f, ['a', 'zzz'], undefined, undefined)).toBe('Tapper, (onbekende tag)') }) }) describe('AVAILABILITY_PICKER', () => { it('maps IDs to "name (start–end)" with seconds stripped', () => { const f = field({ field_type: FormFieldType.AVAILABILITY_PICKER }) const slots = [timeSlot({ id: 'x', name: 'Vrijwilligers afbraak zondag', start_time: '10:00:00', end_time: '16:00:00' })] expect(formatFieldValue(f, ['x'], slots, undefined)) .toBe('Vrijwilligers afbraak zondag (10:00–16:00)') }) it('labels unknown time_slot IDs as "(onbekend tijdslot)"', () => { const f = field({ field_type: FormFieldType.AVAILABILITY_PICKER }) const slots = [timeSlot({ id: 'x' })] expect(formatFieldValue(f, ['x', 'y'], slots, undefined)) .toBe('Vrijdag avond (18:00–23:00), (onbekend tijdslot)') }) it('returns "Laden…" while the time-slots query is still fetching', () => { const f = field({ field_type: FormFieldType.AVAILABILITY_PICKER }) expect(formatFieldValue(f, ['x'], undefined, undefined)).toBe('Laden…') }) }) describe('SECTION_PRIORITY', () => { it('renders "N. Name, …" sorted by priority', () => { const f = field({ field_type: FormFieldType.SECTION_PRIORITY }) const sections = [ section({ id: 's_1', name: 'Hoofdpodium Bar' }), section({ id: 's_2', name: 'Theatertent Bar' }), ] expect(formatFieldValue( f, [{ section_id: 's_1', priority: 1 }, { section_id: 's_2', priority: 2 }], undefined, sections, )).toBe('1. Hoofdpodium Bar, 2. Theatertent Bar') }) it('re-sorts unordered input by priority before rendering', () => { const f = field({ field_type: FormFieldType.SECTION_PRIORITY }) const sections = [section({ id: 's_1', name: 'A' }), section({ id: 's_2', name: 'B' })] expect(formatFieldValue( f, [{ section_id: 's_2', priority: 2 }, { section_id: 's_1', priority: 1 }], undefined, sections, )).toBe('1. A, 2. B') }) it('labels unknown section IDs as "(onbekende sectie)"', () => { const f = field({ field_type: FormFieldType.SECTION_PRIORITY }) const sections = [section({ id: 's_1', name: 'Known' })] expect(formatFieldValue( f, [{ section_id: 's_1', priority: 1 }, { section_id: 'missing', priority: 2 }], undefined, sections, )).toBe('1. Known, 2. (onbekende sectie)') }) it('returns "—" when the value shape is malformed (defensive guard)', () => { const f = field({ field_type: FormFieldType.SECTION_PRIORITY }) // Flat string[] — wrong shape, must not leak [object Object]. expect(formatFieldValue(f, ['s_1', 's_2'], undefined, [section({ id: 's_1', name: 'Known' })])).toBe('—') }) it('returns "Laden…" while the sections query is still fetching', () => { const f = field({ field_type: FormFieldType.SECTION_PRIORITY }) expect(formatFieldValue( f, [{ section_id: 's_1', priority: 1 }], undefined, undefined, )).toBe('Laden…') }) }) describe('scalars', () => { it('formats BOOLEAN true as "Ja", false as "Nee"', () => { const f = field({ field_type: FormFieldType.BOOLEAN }) expect(formatFieldValue(f, true, undefined, undefined)).toBe('Ja') expect(formatFieldValue(f, false, undefined, undefined)).toBe('Nee') }) it('stringifies unknown-type array values via join', () => { const f = field({ field_type: FormFieldType.MULTISELECT }) expect(formatFieldValue(f, ['A', 'B'], undefined, undefined)).toBe('A, B') }) it('stringifies scalars for text-like types', () => { const f = field({ field_type: FormFieldType.TEXT }) expect(formatFieldValue(f, 'hello', undefined, undefined)).toBe('hello') }) }) })