20260913231607

This commit is contained in:
oneao committed 2026-09-13 23:16:08 +08:00
1 parent f3ad727f1c
commit c31329d387
179 files changed
+10846 -2684

No files matched your search

@@ -0,0 +1,140 @@
/**
* FmsField 多态控件渲染器测试。
* 覆盖契约:type→控件映射、checkbox 0/1↔boolean 归一、v-model 透传、
* control-props 直达、fallthrough(class/原生事件)透传、change 转发、
* 默认插槽逃生舱、types 注册表覆盖、selectId(FmsSelect) 双绑回显。
*/
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { h, markRaw } from 'vue'
import FmsField from '@/components/fms-field/FmsField.vue'
import { Checkbox } from '@/components/ui'
// selectId 分支会挂载 FmsSelect,其依赖 @/services/api;桩掉避免真实请求
vi.mock('@/services/api', () => ({
pageDataApi: vi.fn(async () => ({ data: { rows: [], total: 0 } })),
}))
describe('FmsField 类型 → 控件映射', () => {
it('缺省 type 兜底渲染 Input', () => {
const wrapper = mount(FmsField)
expect(wrapper.find('.input-wrapper').exists()).toBe(true)
expect(wrapper.find('input').exists()).toBe(true)
wrapper.unmount()
})
it('未知 type 兜底渲染 Input', () => {
const wrapper = mount(FmsField, { props: { type: 'not-a-real-type' } })
expect(wrapper.find('.input-wrapper').exists()).toBe(true)
wrapper.unmount()
})
it.each([
['textarea', 'textarea'],
['number', 'input[inputmode="decimal"]'],
['money', 'input[inputmode="decimal"]'],
['checkbox', 'label.checkbox'],
['select', '.select-trigger'],
['date', '.fms-date-picker'],
['datetime', '.fms-date-picker'],
])('type=%s 渲染对应控件(%s)', (type, selector) => {
const wrapper = mount(FmsField, { props: { type } })
expect(wrapper.find(selector).exists()).toBe(true)
wrapper.unmount()
})
})
describe('FmsField 值绑定', () => {
it('input:v-model 双向透传', async () => {
const wrapper = mount(FmsField, { props: { modelValue: 'a' } })
expect(wrapper.find('input').element.value).toBe('a')
await wrapper.find('input').setValue('abc')
expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['abc'])
wrapper.unmount()
})
it('checkbox:存储 1 → 勾选;取消勾选 → 抛 0', async () => {
const wrapper = mount(FmsField, { props: { type: 'checkbox', modelValue: 1 } })
const box = wrapper.find('input.checkbox-input')
expect(box.element.checked).toBe(true)
await box.setValue(false)
expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual([0])
wrapper.unmount()
})
it('checkbox:存储 0 → 未勾选;勾选 → 抛 1', async () => {
const wrapper = mount(FmsField, { props: { type: 'checkbox', modelValue: 0 } })
const box = wrapper.find('input.checkbox-input')
expect(box.element.checked).toBe(false)
await box.setValue(true)
expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual([1])
wrapper.unmount()
})
})
describe('FmsField 扩展口子', () => {
it('control-props 直达内部控件', () => {
const wrapper = mount(FmsField, { props: { controlProps: { maxlength: 10 } } })
expect(wrapper.find('input').attributes('maxlength')).toBe('10')
wrapper.unmount()
})
it('fallthrough class 合并到内部控件根节点', () => {
const wrapper = mount(FmsField, { attrs: { class: 'my-field' } })
expect(wrapper.find('.input-wrapper.my-field').exists()).toBe(true)
wrapper.unmount()
})
it('原生事件透传:@keydown 由内部控件冒泡命中', async () => {
const onKeydown = vi.fn()
const wrapper = mount(FmsField, { attrs: { onKeydown } })
await wrapper.find('input').trigger('keydown', { key: 'Enter' })
expect(onKeydown).toHaveBeenCalled()
wrapper.unmount()
})
it('内部控件 change 原样转发', async () => {
const wrapper = mount(FmsField)
await wrapper.find('input').trigger('change')
expect(wrapper.emitted('change')).toBeTruthy()
wrapper.unmount()
})
it('默认插槽整体接管渲染(忽略 type)', () => {
const wrapper = mount(FmsField, {
props: { type: 'select' },
slots: { default: () => h('div', { class: 'custom-control' }, '自定义') },
})
expect(wrapper.find('.custom-control').exists()).toBe(true)
expect(wrapper.find('.select-trigger').exists()).toBe(false)
wrapper.unmount()
})
it('types 注册表覆盖内置类型映射', () => {
const wrapper = mount(FmsField, {
// 组件放入响应式容器需 markRaw,避免 Vue 告警(消费者注册自定义类型时同理)
props: { type: 'input', types: { input: markRaw(Checkbox) } },
})
expect(wrapper.find('label.checkbox').exists()).toBe(true)
expect(wrapper.find('.input-wrapper').exists()).toBe(false)
wrapper.unmount()
})
})
describe('FmsField selectId(FmsSelect 双绑)', () => {
it('渲染 FmsSelect,并用 label 回显选中名', () => {
const wrapper = mount(FmsField, {
props: {
type: 'selectId',
modelValue: '7',
label: '客户甲',
controlProps: { viewName: 'v_customer' },
},
})
expect(wrapper.find('.fms-select').exists()).toBe(true)
expect(wrapper.find('.select-input').element.value).toBe('客户甲')
wrapper.unmount()
})
})