import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'
import { App, ComponentPublicInstance, createApp, defineComponent, h, nextTick } from 'vue'
import { FormConfig } from '../../../../components/form/formConfig'
import { InfoCronConfig } from '../../../../components/form/infoCron'
const ElFormStub = defineComponent({
name: 'ElFormStub',
template: '
'
})
const ElCollapseStub = defineComponent({
name: 'ElCollapseStub',
template: '
'
})
const ElCollapseItemStub = defineComponent({
name: 'ElCollapseItemStub',
props: {
title: { type: String, default: '' }
},
template: ''
})
const InfoFormItemStub = defineComponent({
name: 'InfoFormItemStub',
props: {
item: {
type: Object,
required: true
}
},
template: '
'
})
const InfoInputStub = defineComponent({
name: 'InfoInputStub',
props: {
row: {
type: Object,
required: true
},
modelData: {
type: Object,
required: true
}
},
template: '{{ row.model }}={{ modelData[row.model] }}
'
})
vi.mock('../../../../script/useComponent', () => ({
default: () => ({})
}))
vi.mock('../../../../components/form/infoCron/vue-js-cron/light/src/components/cron-light.vue', () => ({
default: defineComponent({
name: 'CronLightStub',
props: {
modelValue: {
type: String,
default: ''
},
format: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
initialPeriod: {
type: String,
default: ''
},
locale: {
type: String,
default: ''
}
},
emits: ['update:modelValue', 'error'],
template: ''
})
}))
let InfoForm: any
let InfoCron: any
interface RenderResult {
app: App
el: HTMLDivElement
vm: ComponentPublicInstance
}
const renderedApps: RenderResult[] = []
afterEach(() => {
renderedApps.splice(0).forEach(({ app, el }) => {
app.unmount()
el.remove()
})
document.body.innerHTML = ''
})
beforeAll(async () => {
InfoForm = (await import('../../../../components/infoForm/infoForm.vue')).default
InfoCron = (await import('../../../../components/form/infoCron/index.vue')).default
})
const renderInfoForm = async (config: FormConfig, modelData: Record, slots?: Record any>) => {
const el = document.createElement('div')
document.body.appendChild(el)
const app = createApp({
render () {
return h(InfoForm, {
config,
modelData
}, slots || {})
}
})
app.config.globalProperties.$t = (key: string) => key
app.component('el-form', ElFormStub)
app.component('el-collapse', ElCollapseStub)
app.component('el-collapse-item', ElCollapseItemStub)
app.component('info-form-item', InfoFormItemStub)
app.component('InfoFormItem', InfoFormItemStub)
app.component('infoInput', InfoInputStub)
app.component('infoCron', InfoCron)
app.component('infoAddForm', defineComponent({ template: '' }))
app.component('infoDynamic', defineComponent({ template: '' }))
const vm = app.mount(el)
await nextTick()
const result = { app, el, vm }
renderedApps.push(result)
return result
}
describe('components/infoForm/infoForm.vue', () => {
it('透传并渲染 infoSlot,同时分发普通表单组件', async () => {
const config = new FormConfig({
labelWidth: '80px'
})
config.setRule({
type: 'infoSlot',
model: 'customSlotField',
label: '插槽项',
slotName: 'customSlot'
})
config.setRule({
type: 'infoInput',
model: 'name',
label: '名称'
})
await renderInfoForm(
config,
{ name: 'Alice' },
{
customSlot: () => h('div', { class: 'slot-content' }, '透传插槽内容')
}
)
const root = document.body
expect(root.querySelector('.slot-content')).not.toBeNull()
expect(root.querySelector('.slot-content')?.textContent).toBe('透传插槽内容')
expect(root.querySelector('.info-input-stub')).not.toBeNull()
expect(root.querySelector('.info-input-stub')?.textContent).toContain('name=Alice')
expect(root.querySelectorAll('.info-form-item-stub, .el-form-item')).toHaveLength(2)
})
it('将 infoCron 规则实例分发到真实组件并完成最小渲染', async () => {
const config = new FormConfig({
labelWidth: '80px'
})
config.setRule({
type: 'infoCron',
model: 'cron',
label: 'Cron',
placement: 'top'
})
expect(config.rule).toHaveLength(1)
expect(config.rule[0]).toBeInstanceOf(InfoCronConfig)
expect(config.rule[0].type).toBe('infoCron')
expect(config.rule[0].placement).toBe('top')
const modelData = { cron: '' }
await renderInfoForm(config, modelData)
const formItem = document.body.querySelector('.info-form-item-stub[data-model="cron"], .form-item--cron, .el-form-item')
const cronLight = document.body.querySelector('.cron-light-stub') as HTMLElement | null
const cronInput = document.body.querySelector('input') as HTMLInputElement | null
expect(formItem).not.toBeNull()
expect(cronLight).not.toBeNull()
expect(cronLight?.getAttribute('data-format')).toBe('quartz')
expect(cronLight?.getAttribute('data-locale')).toBe('en')
expect(cronLight?.getAttribute('data-disabled')).toBe('false')
expect(cronInput).not.toBeNull()
expect(cronInput?.disabled).toBe(false)
expect(modelData.cron).toBe('0 0 12 * * ?')
})
})