Files
workspace/code/g3soft-erp/web/tests/views/module/module-management/ModuleQueryPanel.spec.ts
T
2026-10-15 22:47:42 +08:00

137 lines
5.4 KiB
TypeScript
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.
/**
* 查询配置面板(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)
})
})