import { beforeAll, describe, expect, it, vi } from 'vitest' import { App, ComponentPublicInstance, createApp, defineComponent, h, nextTick, ref } from 'vue' import { AddFormConfig } from '../../../../components/form/addForm' import { FormRule } from '../../../../components/form/formConfig' const ElTabsStub = defineComponent({ name: 'ElTabsStub', props: { modelValue: { type: String, default: '' }, closable: { type: Boolean, default: false }, addable: { type: Boolean, default: false } }, emits: ['update:modelValue', 'edit', 'tab-click'], template: `
` }) const ElTabPaneStub = defineComponent({ name: 'ElTabPaneStub', props: { label: { type: String, default: '' }, name: { type: String, default: '' } }, template: '
{{ label }}
' }) const ElFormItemStub = defineComponent({ name: 'ElFormItemStub', template: '
' }) const InfoInputStub = defineComponent({ name: 'InfoInputStub', props: { row: { type: Object, required: true } }, template: '' }) vi.mock('../../../../script/useComponent', () => ({ default: () => ({}) })) vi.mock('../../../../components/form/dynamic/index.vue', () => ({ default: defineComponent({ name: 'InfoDynamicStub', template: '
' }) })) let AddForm: any interface RenderResult { app: App el: HTMLDivElement vm: ComponentPublicInstance addFormRef: { handleTabsEdit: (targetName: string, action: string) => void } | null modelData: { list: Array> } afterAdd: ReturnType afterRemove: ReturnType } const renderedApps: RenderResult[] = [] beforeAll(async () => { AddForm = (await import('../../../../components/form/addForm/index.vue')).default }) const renderAddForm = async () => { const afterAdd = vi.fn() const afterRemove = vi.fn() const modelData = { list: [] as Array> } const row = new AddFormConfig({ type: 'infoAddForm', model: 'list', label: '子表单', addable: true, afterAdd, afterRemove, rule: (formRule: FormRule) => { formRule.setInputRule({ type: 'infoInput', model: 'name', label: '名称' }) } }) const el = document.createElement('div') document.body.appendChild(el) const addFormRef = ref(null) const app = createApp({ setup () { return { addFormRef } }, render () { return h(AddForm, { ref: 'addFormRef', row, modelData }) } }) app.config.globalProperties.$t = (key: string) => key app.component('el-tabs', ElTabsStub) app.component('el-tab-pane', ElTabPaneStub) app.component('el-form-item', ElFormItemStub) app.component('infoInput', InfoInputStub) app.component('infoDynamic', defineComponent({ template: '
' })) const vm = app.mount(el) await nextTick() const result = { app, el, vm, addFormRef: addFormRef.value, modelData, afterAdd, afterRemove } renderedApps.push(result) return result } describe('components/form/addForm/index.vue', () => { it('支持新增和删除子表单项,并同步回调与 modelData', async () => { const rendered = await renderAddForm() expect(rendered.modelData.list).toHaveLength(1) expect(rendered.modelData.list[0]).toMatchObject({ rule: 'set_1', name: '' }) expect(document.body.querySelectorAll('.info-input-stub')).toHaveLength(1) expect(rendered.addFormRef).not.toBeNull() rendered.addFormRef?.handleTabsEdit('1', 'add') await nextTick() expect(rendered.modelData.list).toHaveLength(2) expect(rendered.modelData.list[1]).toMatchObject({ rule: 'set_2', name: '' }) expect(rendered.afterAdd).toHaveBeenCalledTimes(1) expect(rendered.afterAdd).toHaveBeenCalledWith(rendered.modelData.list[1]) expect(document.body.querySelectorAll('.info-input-stub')).toHaveLength(1) rendered.addFormRef?.handleTabsEdit('2', 'remove') await nextTick() expect(rendered.modelData.list).toHaveLength(1) expect(rendered.modelData.list[0]).toMatchObject({ rule: 'set_1', name: '' }) expect(rendered.afterRemove).toHaveBeenCalledTimes(1) expect(rendered.afterRemove).toHaveBeenCalledWith(1) expect(document.body.querySelectorAll('.info-input-stub')).toHaveLength(1) }) })