import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { enableAutoUnmount, mount } from '@vue/test-utils' import { ref } from 'vue' import type { FormField } from '../../src/api/types' import MarkdownField from '../../src/components/form/fields/MarkdownField.vue' import MLMarkdownField from '../../src/components/form/fields/MLMarkdownField.vue' import MLTextField from '../../src/components/form/fields/MLTextField.vue' import { FORM_ENABLED_LOCALES } from '../../src/components/form/formContext' import { editablePayload, initialValues, mergeMLValue } from '../../src/components/form/formState' import { isRegistered, rendererFor } from '../../src/components/form/registry' import { resetState } from '../helpers' function field(type: string, name = 'title'): FormField { return { name, label: 'Title', type } as FormField } const enabledLocales = ref(['en', 'pl']) function mlMount(component: typeof MLTextField | typeof MLMarkdownField, props: object) { return mount(component, { props: props as never, attachTo: document.body, global: { provide: { [FORM_ENABLED_LOCALES as symbol]: enabledLocales, }, }, }) } beforeEach(() => { resetState() enabledLocales.value = ['en', 'pl'] }) afterEach(() => { document.body.innerHTML = '' }) enableAutoUnmount(afterEach) describe('ML field registry and nested save body', () => { it('resolves markdown, mltext and mlmarkdown', () => { expect(rendererFor('markdown')).toBe(MarkdownField) expect(rendererFor('mltext')).toBe(MLTextField) expect(rendererFor('mlmarkdown')).toBe(MLMarkdownField) expect(isRegistered('markdown')).toBe(true) expect(isRegistered('mltext')).toBe(true) expect(isRegistered('mlmarkdown')).toBe(true) }) it('sends every locale as a nested record', () => { const fields = [field('mltext'), field('mlmarkdown', 'body')] const payload = editablePayload(fields, { title: { en: 'Hello', pl: 'Witaj' }, body: { en: '# Hi', pl: '# Cześć' }, }) expect(payload).toEqual({ title: { en: 'Hello', pl: 'Witaj' }, body: { en: '# Hi', pl: '# Cześć' }, }) }) it('edits the active locale and copies from another', async () => { const wrapper = mlMount(MLTextField, { field: field('mltext'), modelValue: { en: 'Hello', pl: 'Witaj' }, controlId: 'f-title', }) const input = wrapper.find('input') expect(input.element.value).toBe('Hello') await wrapper.find('[data-ml-locale]').setValue('pl') expect(wrapper.find('input').element.value).toBe('Witaj') await wrapper.find('[data-ml-copy-from]').setValue('en') await wrapper.find('[data-ml-copy]').trigger('click') expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual([{ en: 'Hello', pl: 'Hello' }]) }) it('switches every ML control from one selector', async () => { const title = mlMount(MLTextField, { field: field('mltext'), modelValue: { en: 'Hello', pl: 'Witaj' }, controlId: 'f-title', }) const body = mlMount(MLMarkdownField, { field: field('mlmarkdown', 'body'), modelValue: { en: 'EN', pl: 'PL' }, controlId: 'f-body', }) expect(body.findComponent(MarkdownField).exists()).toBe(true) await title.find('[data-ml-locale]').setValue('pl') expect((body.find('[data-ml-locale]').element as HTMLSelectElement).value).toBe('pl') expect(body.find('textarea').element.value).toBe('PL') }) it('does not execute raw HTML in the markdown preview', async () => { const wrapper = mount(MarkdownField, { props: { field: field('markdown', 'body'), modelValue: '', controlId: 'f-body', }, attachTo: document.body, }) await wrapper.find('[data-markdown-preview]').trigger('click') expect(wrapper.find('script').exists()).toBe(false) expect(wrapper.find('img').exists()).toBe(false) expect((window as unknown as { __ml_xss?: number }).__ml_xss).toBeUndefined() expect(wrapper.find('[data-markdown-preview-pane]').text()).toContain('