import { mount } from '@vue/test-utils' import { describe, expect, it } from 'vitest' import { computed, defineComponent, h, ref } from 'vue' import FieldCheckboxList from '@/components/public-form/FieldCheckboxList.vue' import FieldMultiselect from '@/components/public-form/FieldMultiselect.vue' import FieldRadio from '@/components/public-form/FieldRadio.vue' import FieldSelect from '@/components/public-form/FieldSelect.vue' import { providePublicFormLocale } from '@/composables/publicFormInjection' import { FormFieldType } from '@form-schema/types/formBuilder' import type { OptionSpec, PublicFormField } from '@form-schema/types/formBuilder' const stubs = { VRadioGroup: { name: 'VRadioGroup', template: '
' }, VRadio: { name: 'VRadio', props: ['value', 'label'], template: '
', }, VCheckbox: { name: 'VCheckbox', props: ['modelValue', 'label'], template: '
', }, AppSelect: { name: 'AppSelect', props: ['modelValue', 'items', 'itemTitle', 'itemValue', 'label'], template: `
{{ item.title }}
`, }, } function fieldOf(field_type: PublicFormField['field_type'], options: OptionSpec[]): PublicFormField { return { id: 'f_1', slug: 'choice', field_type, label: 'Choice', help_text: null, options, available_tags: null, validation_rules: null, is_required: false, display_width: 'full', conditional_logic: null, sort_order: 1, form_schema_section_id: null, } } function harness(component: any, field: PublicFormField, locale: string) { // Tiny wrapper that calls providePublicFormLocale before rendering the // target component, mimicking what [public_token].vue does at the page // root. const Wrapper = defineComponent({ setup() { providePublicFormLocale(ref(locale)) return () => h(component, { field, modelValue: null }) }, }) return mount(Wrapper, { global: { stubs } }) } const optionsSample: OptionSpec[] = [ { value: 'red', label: 'Red', sort_order: 0, translations: { nl: 'Rood', de: 'Rot' } }, { value: 'green', label: 'Green', sort_order: 1 }, // no translations — fallback ] describe('Option-bearing field locale resolution', () => { describe('FieldRadio', () => { it('prefers translations[locale] over the default label', () => { const wrapper = harness(FieldRadio, fieldOf(FormFieldType.RADIO, optionsSample), 'nl') const radios = wrapper.findAll('.v-radio-stub') expect(radios.length).toBe(2) expect(radios[0].attributes('data-label')).toBe('Rood') }) it('falls back to label when translation is missing for the current locale', () => { const wrapper = harness(FieldRadio, fieldOf(FormFieldType.RADIO, optionsSample), 'nl') const radios = wrapper.findAll('.v-radio-stub') expect(radios[1].attributes('data-label')).toBe('Green') }) }) describe('FieldSelect', () => { it('emits translated title for matching locale', () => { const wrapper = harness(FieldSelect, fieldOf(FormFieldType.SELECT, optionsSample), 'de') const items = wrapper.findAll('.stub-item') expect(items[0].attributes('data-title')).toBe('Rot') }) it('falls back to label on missing translation', () => { const wrapper = harness(FieldSelect, fieldOf(FormFieldType.SELECT, optionsSample), 'de') const items = wrapper.findAll('.stub-item') expect(items[1].attributes('data-title')).toBe('Green') }) }) describe('FieldMultiselect', () => { it('emits translated title for matching locale', () => { const wrapper = harness(FieldMultiselect, fieldOf(FormFieldType.MULTISELECT, optionsSample), 'nl') const items = wrapper.findAll('.stub-item') expect(items[0].attributes('data-title')).toBe('Rood') }) it('falls back to label on missing translation', () => { const wrapper = harness(FieldMultiselect, fieldOf(FormFieldType.MULTISELECT, optionsSample), 'nl') const items = wrapper.findAll('.stub-item') expect(items[1].attributes('data-title')).toBe('Green') }) }) describe('FieldCheckboxList', () => { it('emits translated label for matching locale', () => { const wrapper = harness(FieldCheckboxList, fieldOf(FormFieldType.CHECKBOX_LIST, optionsSample), 'nl') const checkboxes = wrapper.findAll('.v-checkbox-stub') expect(checkboxes[0].attributes('data-label')).toBe('Rood') }) it('falls back to label on missing translation', () => { const wrapper = harness(FieldCheckboxList, fieldOf(FormFieldType.CHECKBOX_LIST, optionsSample), 'nl') const checkboxes = wrapper.findAll('.v-checkbox-stub') expect(checkboxes[1].attributes('data-label')).toBe('Green') }) }) it('default-locale fallback (no provider on the tree) uses the option label as-is', () => { // No providePublicFormLocale in the wrapper — usePublicFormLocale // defaults to 'nl', which doesn't appear in options that only carry // 'de' translations, so we get the raw label. const Wrapper = defineComponent({ setup() { return () => h(FieldRadio, { field: fieldOf(FormFieldType.RADIO, [ { value: 'a', label: 'Apple', sort_order: 0, translations: { de: 'Apfel' } }, ]), modelValue: null, }) }, }) const wrapper = mount(Wrapper, { global: { stubs } }) const radios = wrapper.findAll('.v-radio-stub') expect(radios[0].attributes('data-label')).toBe('Apple') }) })