Files
crewli/apps/portal/tests/components/public-form/FieldRenderer.test.ts
bert.hausmans b159fdcc26 test(portal): add Vitest setup and public-form tests
Introduces vitest config, jsdom setup, and first suites covering
FieldRenderer dispatch and useConditionalLogic evaluation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 17:21:04 +02:00

103 lines
4.8 KiB
TypeScript

import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import FieldRenderer from '@/components/public-form/FieldRenderer.vue'
import { FormFieldType } from '@/types/formBuilder'
import type { PublicFormField } from '@/types/formBuilder'
function makeField(partial: Partial<PublicFormField>): PublicFormField {
return {
id: partial.id ?? 'id',
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 mountRenderer(field: PublicFormField, allValues: Record<string, unknown> = {}) {
return mount(FieldRenderer, {
props: { field, modelValue: undefined, allValues },
global: {
stubs: {
VCol: { name: 'VCol', template: '<div class="v-col-stub"><slot/></div>' },
VAlert: { name: 'VAlert', template: '<div class="v-alert-stub"><slot/></div>' },
FieldText: { name: 'FieldText', template: '<div class="field-text-stub"/>' },
FieldTextarea: { name: 'FieldTextarea', template: '<div class="field-textarea-stub"/>' },
FieldEmail: { name: 'FieldEmail', template: '<div class="field-email-stub"/>' },
FieldPhone: { name: 'FieldPhone', template: '<div class="field-phone-stub"/>' },
FieldNumber: { name: 'FieldNumber', template: '<div class="field-number-stub"/>' },
FieldDate: { name: 'FieldDate', template: '<div class="field-date-stub"/>' },
FieldBoolean: { name: 'FieldBoolean', template: '<div class="field-boolean-stub"/>' },
FieldRadio: { name: 'FieldRadio', template: '<div class="field-radio-stub"/>' },
FieldSelect: { name: 'FieldSelect', template: '<div class="field-select-stub"/>' },
FieldMultiselect: { name: 'FieldMultiselect', template: '<div class="field-multiselect-stub"/>' },
FieldCheckboxList: { name: 'FieldCheckboxList', template: '<div class="field-checkboxlist-stub"/>' },
FieldHeading: { name: 'FieldHeading', template: '<div class="field-heading-stub"/>' },
FieldParagraph: { name: 'FieldParagraph', template: '<div class="field-paragraph-stub"/>' },
FieldUrl: { name: 'FieldUrl', template: '<div class="field-url-stub"/>' },
},
},
})
}
describe('FieldRenderer', () => {
it.each<[string, string]>([
[FormFieldType.TEXT, 'field-text-stub'],
[FormFieldType.TEXTAREA, 'field-textarea-stub'],
[FormFieldType.EMAIL, 'field-email-stub'],
[FormFieldType.PHONE, 'field-phone-stub'],
[FormFieldType.NUMBER, 'field-number-stub'],
[FormFieldType.DATE, 'field-date-stub'],
[FormFieldType.BOOLEAN, 'field-boolean-stub'],
[FormFieldType.RADIO, 'field-radio-stub'],
[FormFieldType.SELECT, 'field-select-stub'],
[FormFieldType.MULTISELECT, 'field-multiselect-stub'],
[FormFieldType.CHECKBOX_LIST, 'field-checkboxlist-stub'],
[FormFieldType.HEADING, 'field-heading-stub'],
[FormFieldType.PARAGRAPH, 'field-paragraph-stub'],
[FormFieldType.URL, 'field-url-stub'],
])('dispatches to the right component for %s', (fieldType, className) => {
const wrapper = mountRenderer(makeField({ field_type: fieldType as typeof FormFieldType[keyof typeof FormFieldType] }))
expect(wrapper.find(`.${className}`).exists()).toBe(true)
})
it.each<string>([
FormFieldType.TAG_PICKER,
FormFieldType.AVAILABILITY_PICKER,
FormFieldType.SECTION_PRIORITY,
FormFieldType.FILE_UPLOAD,
FormFieldType.IMAGE_UPLOAD,
FormFieldType.SIGNATURE,
FormFieldType.TABLE_ROWS,
FormFieldType.DATETIME,
])('renders placeholder alert for out-of-scope type %s', fieldType => {
const wrapper = mountRenderer(makeField({ field_type: fieldType as typeof FormFieldType[keyof typeof FormFieldType] }))
expect(wrapper.find('.v-alert-stub').exists()).toBe(true)
expect(wrapper.text()).toContain('binnenkort ondersteund')
})
it('hides the field when conditional logic evaluates to false', () => {
const field = makeField({
field_type: FormFieldType.TEXT,
conditional_logic: {
show_when: { all: [{ field_slug: 'gate', operator: 'equals', value: 'yes' }] },
},
})
const hidden = mountRenderer(field, { gate: 'no' })
expect(hidden.find('.field-text-stub').exists()).toBe(false)
expect(hidden.find('.v-col-stub').exists()).toBe(false)
const shown = mountRenderer(field, { gate: 'yes' })
expect(shown.find('.field-text-stub').exists()).toBe(true)
})
})