This commit is contained in:
oneao committed 2026-10-15 22:47:42 +08:00
1 parent bf9dca19de
commit e7c84a82a2
31 files changed
+4063 -2362

No files matched your search

@@ -0,0 +1,136 @@
/**
* 查询配置面板(query JSON,schemaVersion 4):只配工作队列页签。
*
* 这里测的是**结构与数据往返**:分组渲染、建组即建页签、编码自动派生、
* 组名就地改要改整组、旧的查询字段配置在回写时被清掉。
* G3Table 在 happy-dom 里没有真实尺寸,行内编辑与行拖拽是组件库自己的活,
* 用桩替换掉(本面板只负责把列定义与数据源接上去)。
*/
import { describe, expect, it } from 'vitest'
import { mount } from '@vue/test-utils'
import ModuleQueryPanel from '@/views/module/module-management/ModuleQueryPanel.vue'
import type { SchemaJson } from '@/utils/schemaJson'
function schema(views: Array<Record<string, unknown>> = []): SchemaJson {
return { schemaVersion: 4, views }
}
/**
* 模拟父级 v-model:query:emit 回来要显式写回 prop,
* 否则复现不了「草稿回写 → 父级再传下来」这一轮往返。
*/
function mountPanel(views: Array<Record<string, unknown>> = []) {
const wrapper = mount(ModuleQueryPanel, {
props: {
query: schema(views),
'onUpdate:query': (value: SchemaJson) => wrapper.setProps({ query: value }),
},
global: { stubs: { G3Table: true } },
})
return wrapper
}
/** 当前草稿里的页签行(面板对外就是这份 query JSON) */
function draftViews(wrapper: ReturnType<typeof mountPanel>): Array<Record<string, unknown>> {
return (wrapper.props('query') as SchemaJson).views as Array<Record<string, unknown>>
}
function groupNames(wrapper: ReturnType<typeof mountPanel>): string[] {
return wrapper.findAll('.mm-groups__name').map((el) => (el.element as HTMLInputElement).value)
}
/** 改组名:业务上走 change(失焦 / 回车提交),这里照同一条路触发 */
async function renameFirstGroup(wrapper: ReturnType<typeof mountPanel>, name: string) {
const input = wrapper.find('.mm-groups__name')
await input.setValue(name)
await input.trigger('change')
await wrapper.vm.$nextTick()
}
describe('查询配置面板(工作队列页签)', () => {
it('按 group 归组:分组条上每组一个 chip,顺序跟着组内最小 order 走', () => {
const wrapper = mountPanel([
{ code: 'sail', label: '已开航', group: '状态', order: 30 },
{ code: 'all', label: '全部', group: '状态', order: 10 },
{ code: 'month', label: '本月', group: '时间', order: 20 },
])
expect(groupNames(wrapper)).toEqual(['状态', '时间'])
})
it('历史配置没写 group 的页签落到「默认」组(组从行反推,不存在无组的页签)', () => {
const wrapper = mountPanel([{ code: 'all', label: '全部', order: 10 }])
expect(groupNames(wrapper)).toEqual(['默认'])
})
it('新增页签组:建组的同时建出组内第一个页签,编码自动派生(空编码落库会被丢掉)', async () => {
const wrapper = mountPanel()
await wrapper.find('.mm-query__bar button').trigger('click')
await wrapper.vm.$nextTick()
expect(groupNames(wrapper)).toEqual(['分组 1'])
const views = draftViews(wrapper)
expect(views).toHaveLength(1)
expect(views[0].group).toBe('分组 1')
expect(views[0].code).toBe('view_1')
// 组里第一个页签自动成为组内默认:一个组总要有一个默认选中的
expect(views[0].isDefault).toBe(true)
})
it('再加一组时编码继续派生,不会与已有页签撞号', async () => {
const wrapper = mountPanel([{ code: 'view_1', label: '全部', group: '状态', order: 10 }])
await wrapper.find('.mm-query__bar button').trigger('click')
await wrapper.vm.$nextTick()
expect(draftViews(wrapper)[1].code).toBe('view_2')
})
it('组名就地改:改的是整组(组是共享实体,不能只改一行)', async () => {
const wrapper = mountPanel([
{ code: 'all', label: '全部', group: '状态', order: 10 },
{ code: 'sail', label: '已开航', group: '状态', order: 20 },
])
await renameFirstGroup(wrapper, '运行状态')
expect(groupNames(wrapper)).toEqual(['运行状态'])
expect(draftViews(wrapper).every((row) => row.group === '运行状态')).toBe(true)
})
it('组名改成已存在的组名时拒绝(否则两个组会被无声合并)', async () => {
const wrapper = mountPanel([
{ code: 'a', label: '全部', group: '状态', order: 10 },
{ code: 'b', label: '本月', group: '时间', order: 20 },
])
await renameFirstGroup(wrapper, '时间')
expect(groupNames(wrapper)).toEqual(['状态', '时间'])
})
it('回写时把不再使用的 queryFields / keywordSearch / quickFilters 一并清掉', async () => {
const wrapper = mountPanel()
// 载入一份带旧配置的 schema:适配层只认 views,其余键由回写统一清理
await wrapper.setProps({
query: {
schemaVersion: 3,
views: [{ code: 'all', label: '全部', order: 10 }],
keywordSearch: { fields: ['b_name'] },
quickFilters: [{ field: 'b_name', order: 10 }],
queryFields: { b_name: { component: 'input', operator: 'like' } },
},
})
// 触发一次回写(新增一组)
await wrapper.find('.mm-query__bar button').trigger('click')
await wrapper.vm.$nextTick()
const next = wrapper.props('query') as SchemaJson
expect(next.queryFields).toBeUndefined()
expect(next.keywordSearch).toBeUndefined()
expect(next.quickFilters).toBeUndefined()
expect(next.schemaVersion).toBe(4)
})
})