Files
workspace/code/fms/fms-vue/tests/components/form.spec.js
T
2026-09-17 21:29:08 +08:00

183 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { afterEach, describe, it, expect } from 'vitest'
import { h, nextTick, ref } from 'vue'
import { flushPromises, mount } from '@vue/test-utils'
import Form from '@/components/ui/form/form.vue'
import FormItem from '@/components/ui/form/form-item.vue'
import { resetUIConfig, setUIConfig, uiConfig } from '@/components/ui/config'
const model = () =>
ref({
code: 'a',
name: 'b',
note: 'c',
})
function mountForm(columns = 1, extraProps = {}) {
return mount(Form, {
props: { model: model().value, columns, ...extraProps },
slots: {
default: () => [
h(FormItem, { name: 'code', label: '编码' }, { default: () => h('input') }),
h(FormItem, { name: 'name', label: '名称' }, { default: () => h('input') }),
h(FormItem, { name: 'note', label: '备注', span: 2 }, { default: () => h('input') }),
],
},
})
}
describe('Form 多列网格布局', () => {
it('columns=1 时保持原布局(无网格 class)', () => {
const wrapper = mountForm()
expect(wrapper.classes()).not.toContain('fms-form-grid')
expect(wrapper.attributes('style')).toBeUndefined()
})
it('columns>1 时启用网格并生成列模板', () => {
const wrapper = mountForm(2)
expect(wrapper.classes()).toContain('fms-form-grid')
expect(wrapper.element.style.gridTemplateColumns).toBe('repeat(2, minmax(0, 1fr))')
})
it('span>1 的 FormItem 跨列', () => {
const wrapper = mountForm(2)
const items = wrapper.findAllComponents(FormItem)
const noteItem = items.find((i) => i.props('name') === 'note')
expect(noteItem.element.style.gridColumn).toBe('span 2')
const codeItem = items.find((i) => i.props('name') === 'code')
expect(codeItem.element.style.gridColumn).toBe('')
})
it('span 超过列数时取整行', () => {
const wrapper = mount(Form, {
props: { model: model().value, columns: 3 },
slots: {
default: () => [
h(FormItem, { name: 'code', label: '编码', span: 5 }, { default: () => h('input') }),
],
},
})
const item = wrapper.findComponent(FormItem)
expect(item.element.style.gridColumn).toBe('span 3')
})
it('maxWidth 数字按 px 处理', () => {
const wrapper = mountForm(2, { maxWidth: 720 })
expect(wrapper.element.style.maxWidth).toBe('720px')
})
it('vertical 布局下 label 在上', () => {
const wrapper = mountForm(2, { layout: 'vertical' })
const item = wrapper.findComponent(FormItem)
expect(item.classes()).toContain('fms-form-item-vertical')
expect(item.find('.fms-form-label-vertical').exists()).toBe(true)
})
})
describe('Form 全局配置(uiConfig)', () => {
afterEach(() => resetUIConfig())
it('未传 layout 时取全局配置', () => {
setUIConfig({ form: { layout: 'vertical' } })
const wrapper = mountForm()
expect(wrapper.classes()).toContain('fms-form-vertical')
expect(wrapper.findComponent(FormItem).classes()).toContain('fms-form-item-vertical')
})
it('显式 layout 覆盖全局配置', () => {
setUIConfig({ form: { layout: 'vertical' } })
const wrapper = mountForm(1, { layout: 'horizontal' })
expect(wrapper.classes()).toContain('fms-form-horizontal')
expect(wrapper.findComponent(FormItem).classes()).not.toContain('fms-form-item-vertical')
})
it('setUIConfig 局部合并,未提及的键保持原值', () => {
setUIConfig({ form: { labelAlign: 'left' } })
expect(uiConfig.form.labelAlign).toBe('left')
expect(uiConfig.form.layout).toBe('horizontal')
setUIConfig({ form: { layout: 'vertical' } })
expect(uiConfig.form.labelAlign).toBe('left')
})
it('全局 validateTrigger 生效:change 改为 blur 后值变化不立即报红', async () => {
setUIConfig({ form: { validateTrigger: 'blur' } })
const model = ref({ code: '' })
const wrapper = mount(Form, {
props: { model: model.value, rules: { code: [{ required: true, message: '必填' }] } },
slots: {
default: () => [
h(FormItem, { name: 'code', label: '编码' }, { default: () => h('input') }),
],
},
})
model.value.code = 'a'
await nextTick()
model.value.code = ''
await nextTick()
await flushPromises()
expect(wrapper.findComponent(FormItem).classes()).not.toContain('fms-form-item-error')
})
it('独立使用的 FormItem(无 Form 包裹)也读全局 layout', () => {
setUIConfig({ form: { layout: 'vertical' } })
const wrapper = mount(FormItem, {
props: { name: 'code', label: '编码' },
slots: { default: () => h('input') },
})
expect(wrapper.classes()).toContain('fms-form-item-vertical')
})
})
describe('Form 必填校验与 FormItem 错误展示', () => {
function mountRequiredForm(rules, modelValue = { code: '' }) {
const model = ref(modelValue)
const wrapper = mount(Form, {
props: { model: model.value, rules },
slots: {
default: () => [h(FormItem, { name: 'code', label: '编码' }, { default: () => h('input') })],
},
})
return { wrapper, model }
}
it('必填为空时提交:FormItem 下方显示错误并标红', async () => {
const { wrapper } = mountRequiredForm({ code: [{ required: true, message: '请填写编码' }] })
await wrapper.find('form').trigger('submit')
await flushPromises()
const item = wrapper.findComponent(FormItem)
expect(item.classes()).toContain('fms-form-item-error')
const help = item.find('.fms-form-item-help-error')
expect(help.exists()).toBe(true)
expect(help.text()).toBe('请填写编码')
expect(wrapper.emitted('submitFailed')).toHaveLength(1)
})
it('message 为函数时按校验时求值(动态文案)', async () => {
const { wrapper } = mountRequiredForm({ code: [{ required: true, message: () => '请填写分类编码' }] })
await wrapper.find('form').trigger('submit')
await flushPromises()
const help = wrapper.findComponent(FormItem).find('.fms-form-item-help-error')
expect(help.text()).toBe('请填写分类编码')
})
it('validateAll 暴露并返回带错误的字段列表', async () => {
const { wrapper } = mountRequiredForm({ code: [{ required: true, message: '请填写编码' }] })
const errors = await wrapper.vm.validateAll()
expect(errors).toHaveLength(1)
expect(errors[0].name).toBe('code')
expect(errors[0].errors).toEqual(['请填写编码'])
})
it('修正必填值后错误清除', async () => {
const { wrapper, model } = mountRequiredForm({ code: [{ required: true, message: '请填写编码' }] })
await wrapper.find('form').trigger('submit')
await flushPromises()
expect(wrapper.findComponent(FormItem).classes()).toContain('fms-form-item-error')
model.value.code = 'abc'
await nextTick()
await flushPromises()
const item = wrapper.findComponent(FormItem)
expect(item.classes()).not.toContain('fms-form-item-error')
expect(item.find('.fms-form-item-help-error').exists()).toBe(false)
})
})