import { mount } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import { afterEach, beforeEach, describe, expect, it } from 'vitest' import FmsQueryControl from '@/components/fms-module-list/FmsQueryControl.vue' import FmsQueryToolbar from '@/components/fms-module-list/FmsQueryToolbar.vue' import FmsAdvancedQueryPanel from '@/components/fms-module-list/FmsAdvancedQueryPanel.vue' import FmsField from '@/components/fms-field/FmsField.vue' import { resetUIConfig, setUIConfig } from '@/components/ui' /** 构造一个查询条件项(字段 + 配置),供工具栏布局用例复用 */ const queryItem = (field) => ({ field: { b_field: field, b_type: 'input' }, config: { b_operator: 'like', b_component: 'input' }, }) /** 构造一个区间条件项:字段类型决定两端控件的形态 */ const rangeQueryItem = (bType) => ({ field: { b_field: 'created', b_type: bType }, config: { b_operator: 'between', b_component: bType }, }) describe('fms-module-list components', () => { beforeEach(() => setActivePinia(createPinia())) afterEach(() => resetUIConfig()) it('mounts a text query control with the new UI kit', () => { const wrapper = mount(FmsQueryControl, { props: { item: { field: { b_field: 'name', b_type: 'input' }, config: { b_operator: 'like', b_component: 'input' }, }, modelValue: '', }, }) expect(wrapper.find('input').exists()).toBe(true) }) it('mounts an empty toolbar without legacy Ant components', () => { const wrapper = mount(FmsQueryToolbar) expect(wrapper.find('.fms-query-toolbar').exists()).toBe(true) expect(wrapper.html()).not.toContain(' { const mountToolbar = () => mount(FmsQueryToolbar, { props: { queryItems: [queryItem('b_name')], queryLayout: { area: { b_name: 'quick' }, order: { b_name: 10 } }, }, }) // 中文(默认):横排,label 在左 const zh = mountToolbar() const item = zh.find('.query-field') expect(item.classes()).toContain('fms-form-item') expect(item.classes()).not.toContain('fms-form-item-vertical') expect(item.find('.fms-form-item-label').text()).toBe('b_name') // 定宽标签会在短标签后拖出一段空白,查询区按内容收缩 expect(item.find('.fms-form-item-label').attributes('style')).toContain('width: auto') zh.unmount() // 切到非中文:竖排,label 在上 setUIConfig({ form: { layout: 'vertical' } }) const en = mountToolbar() expect(en.find('.query-field').classes()).toContain('fms-form-item-vertical') en.unmount() }) it('查询条件网格列数按条件数收缩(只有一个条件时不占 4 列宽)', () => { const one = mount(FmsQueryToolbar, { props: { queryItems: [queryItem('b_name')], queryLayout: { area: { b_name: 'quick' }, order: { b_name: 10 } }, }, }) expect(one.find('.query-grid').element.style.gridTemplateColumns).toBe( 'repeat(1, minmax(0, 200px))', ) one.unmount() const four = mount(FmsQueryToolbar, { props: { queryItems: [queryItem('a'), queryItem('b'), queryItem('c'), queryItem('d')], queryLayout: { area: { a: 'quick', b: 'quick', c: 'quick', d: 'quick' }, order: {}, }, }, }) expect(four.find('.query-grid').element.style.gridTemplateColumns).toBe( 'repeat(4, minmax(0, 200px))', ) four.unmount() }) it('高级查询行间连接符表达行与行的连接:≥2 项才出现,点击切换后一项的 join', async () => { const state = { nodes: [ { id: 'n1', join: 'and', field: 'name', operator: 'like', value: 'a' }, { id: 'n2', join: 'and', field: 'name', operator: 'like', value: 'b' }, ], groups: [], } const wrapper = mount(FmsAdvancedQueryPanel, { props: { open: true, items: [], modelValue: state }, }) const pill = wrapper.find('.filter-joiner .joiner-pill') expect(pill.exists()).toBe(true) expect(pill.text()).toBe('且') await pill.trigger('click') expect(state.nodes[1].join).toBe('or') expect(wrapper.find('.filter-joiner .joiner-pill').text()).toBe('或') wrapper.unmount() }) it('只有 1 个条件时不显示行间连接符(没有连接对象),条件行直接可见', () => { const wrapper = mount(FmsAdvancedQueryPanel, { props: { open: true, items: [], modelValue: { logic: 'and', nodes: [{ id: 'n1', field: 'name', operator: 'like', value: '' }], groups: [], }, }, }) expect(wrapper.find('.filter-joiner').exists()).toBe(false) expect(wrapper.find('.filter-row').exists()).toBe(true) wrapper.unmount() }) it('日期区间拆成两个独立控件加分隔符,控件类型随字段类型走', () => { const dateRange = mount(FmsQueryControl, { props: { item: rangeQueryItem('date'), modelValue: ['', ''] }, }) const dateFields = dateRange.findAllComponents(FmsField) expect(dateFields.map((field) => field.props('type'))).toEqual(['date', 'date']) // date 只到日,不需要覆盖控件自身的 format expect(dateFields[0].props('controlProps').format).toBeUndefined() expect(dateRange.find('.fms-query-control__separator').exists()).toBe(true) dateRange.unmount() const datetimeRange = mount(FmsQueryControl, { props: { item: rangeQueryItem('datetime'), modelValue: ['', ''] }, }) const datetimeFields = datetimeRange.findAllComponents(FmsField) expect(datetimeFields.map((field) => field.props('type'))).toEqual(['datetime', 'datetime']) // datetime 端点必须到秒:分钟精度下「当天末」表达不出来,结束端默认时间会被归零成 23:59 expect(datetimeFields.map((field) => field.props('controlProps').format)).toEqual([ 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss', ]) datetimeRange.unmount() }) it('日期区间两端各自只受另一端约束,并带当天起 / 当天末的默认时间', () => { const wrapper = mount(FmsQueryControl, { props: { item: rangeQueryItem('date'), modelValue: ['2026-01-10', '2026-01-20'] }, }) const [start, end] = wrapper.findAllComponents(FmsField) const startProps = start.props('controlProps') const endProps = end.props('controlProps') expect(startProps.timeDefault).toBe('start') expect(endProps.timeDefault).toBe('end') // 开始端:只禁晚于结束端,往前扩区间不受限 expect(startProps.disabledDate(new Date('2026-01-25'))).toBe(true) expect(startProps.disabledDate(new Date('2026-01-05'))).toBe(false) // 结束端:只禁早于开始端,往后扩区间不受限 expect(endProps.disabledDate(new Date('2026-01-05'))).toBe(true) expect(endProps.disabledDate(new Date('2026-01-25'))).toBe(false) wrapper.unmount() }) it('日期区间单端变更只写对应下标,另一端保持', () => { const wrapper = mount(FmsQueryControl, { props: { item: rangeQueryItem('date'), modelValue: ['2026-01-10', '2026-01-20'] }, }) const [start, end] = wrapper.findAllComponents(FmsField) start.vm.$emit('update:modelValue', '2026-01-05') expect(wrapper.emitted('update:modelValue').at(-1)[0]).toEqual(['2026-01-05', '2026-01-20']) end.vm.$emit('update:modelValue', '2026-01-31') expect(wrapper.emitted('update:modelValue').at(-1)[0]).toEqual(['2026-01-10', '2026-01-31']) wrapper.unmount() }) it('数值区间仍是两个输入框加分隔符', () => { const wrapper = mount(FmsQueryControl, { props: { item: rangeQueryItem('number'), modelValue: ['', ''] }, }) expect(wrapper.findAll('input')).toHaveLength(2) expect(wrapper.find('.fms-query-control__separator').exists()).toBe(true) wrapper.unmount() }) })