u
This commit is contained in:
1 parent
e434374db5
commit
b4498e5350
31 files changed
+2007
-294
No files matched your search
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 侧栏菜单项:折叠态只显示图标。
|
||||
*
|
||||
* 回归背景:分组分支在折叠态走的是 G3Dropdown(触发器里只有图标),
|
||||
* 而叶子分支的名称没跟着折叠态隐藏 —— 折叠后行里仍是「图标 + 名称」,
|
||||
* 侧栏只剩 collapseWidth 那么宽(图标+间距就占掉二十几像素),
|
||||
* 名称被裁成一两个字加省略号,比不显示更糟。
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { ref } from 'vue'
|
||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||
import SidebarMenuItem from '@/layouts/SidebarMenuItem.vue'
|
||||
import type { SidebarMenuNode } from '@/types/menu'
|
||||
|
||||
const LEAF: SidebarMenuNode = {
|
||||
key: 'approval_todo',
|
||||
title: '我的待办',
|
||||
path: '/approval/todo',
|
||||
icon: { template: '<i class="stub-icon" />' },
|
||||
}
|
||||
|
||||
function mountLeaf(collapsed: boolean) {
|
||||
return mount(SidebarMenuItem, {
|
||||
props: { item: LEAF, level: 0 },
|
||||
global: {
|
||||
plugins: [
|
||||
createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [{ path: '/approval/todo', component: { template: '<div />' } }],
|
||||
}),
|
||||
],
|
||||
provide: {
|
||||
'sidebar-menu': {
|
||||
collapsed: ref(collapsed),
|
||||
isLeafActive: () => false,
|
||||
isGroupActive: () => false,
|
||||
isGroupOpen: () => false,
|
||||
toggleGroup: () => {},
|
||||
selectPath: () => {},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
describe('SidebarMenuItem 叶子项', () => {
|
||||
it('展开态:图标与名称都在,不需要 title 提示', () => {
|
||||
const wrapper = mountLeaf(false)
|
||||
|
||||
expect(wrapper.find('.stub-icon').exists()).toBe(true)
|
||||
expect(wrapper.find('.layout-sidebar__label').text()).toBe('我的待办')
|
||||
expect(wrapper.find('a').attributes('title')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('折叠态:只渲染图标,名称不进 DOM,改为 title 提示', () => {
|
||||
const wrapper = mountLeaf(true)
|
||||
|
||||
expect(wrapper.find('.stub-icon').exists()).toBe(true)
|
||||
expect(wrapper.find('.layout-sidebar__label').exists()).toBe(false)
|
||||
expect(wrapper.find('a').attributes('title')).toBe('我的待办')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* 自动编码面板(s_autocode):惰性建行 + 实时预览 + 校验。
|
||||
*
|
||||
* 关键点:模块从未配置自动编码时草稿保持空数组(打开面板即建行会把「无变更」
|
||||
* diff 成一条 insert),只有用户首次操作才落行;且 defineModel 写入后不能立刻
|
||||
* 回读 prop(要下一轮才回传),所以建行后返回的是 reactive 代理行。
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { G3Switch } from '@g3soft/ui'
|
||||
import ModuleAutoCodePanel from '@/views/module/module-management/ModuleAutoCodePanel.vue'
|
||||
import type { ModuleAutoCodeRow } from '@/views/module/module-management/utils'
|
||||
|
||||
const FIELDS = [
|
||||
{ b_field: 'b_id', b_name: '编码', b_type: 'input', b_canuse: 1 },
|
||||
{ b_field: 'b_no', b_name: '业务单号', b_type: 'input', b_canuse: 1 },
|
||||
{ b_field: 'b_bz', b_name: '备注', b_type: 'textarea', b_canuse: 1 },
|
||||
{ b_field: 'b_amount', b_name: '金额', b_type: 'money', b_canuse: 1 },
|
||||
{ b_field: 'b_off', b_name: '停用字段', b_type: 'input', b_canuse: 0 },
|
||||
]
|
||||
|
||||
/** 造一行规则:只写关心的字段,其余取启用态的常用默认值 */
|
||||
function row(overrides: Partial<ModuleAutoCodeRow> = {}): ModuleAutoCodeRow {
|
||||
return {
|
||||
b_module_id: 'm1',
|
||||
b_field: 'b_no',
|
||||
b_prefix: '',
|
||||
b_dateformat: 'yyyyMM',
|
||||
b_separator: '-',
|
||||
b_seqwidth: 5,
|
||||
b_resettype: 'month',
|
||||
b_startvalue: 1,
|
||||
b_currentperiod: null,
|
||||
b_currentvalue: 0,
|
||||
b_canuse: 1,
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
/** 模拟父级 v-model:autocode:emit 回来要显式写回 prop,否则复现不了「立刻回读旧值」的问题 */
|
||||
function mountPanel(autocode: ModuleAutoCodeRow[] = []) {
|
||||
const wrapper = mount(ModuleAutoCodePanel, {
|
||||
props: {
|
||||
moduleId: 'm1',
|
||||
fields: FIELDS,
|
||||
autocode,
|
||||
'onUpdate:autocode': (value: ModuleAutoCodeRow[]) => wrapper.setProps({ autocode: value }),
|
||||
},
|
||||
})
|
||||
return wrapper
|
||||
}
|
||||
|
||||
describe('自动编码面板', () => {
|
||||
it('首次拨「启用」时惰性建行并写回 b_canuse(defineModel 不能写完立刻回读)', async () => {
|
||||
const wrapper = mountPanel()
|
||||
|
||||
// 模块从未配置自动编码:草稿为空,此时拨开关会走 ensureRow 建行
|
||||
wrapper.findComponent(G3Switch).vm.$emit('update:modelValue', true)
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
const emitted = wrapper.emitted('update:autocode')
|
||||
expect(emitted).toBeTruthy()
|
||||
const created = emitted![0][0] as ModuleAutoCodeRow[]
|
||||
expect(created[0].b_canuse).toBe(1)
|
||||
expect(created[0].b_module_id).toBe('m1')
|
||||
// 业务编号字段自动取第一个可用文本字段(排除主键 b_id、非文本类型与停用字段)
|
||||
expect(created[0].b_field).toBe('b_no')
|
||||
})
|
||||
|
||||
it('已有一行时就地改,不再新建也不重新 emit 整个数组', async () => {
|
||||
// 传进去的数组即父级持有的草稿:断言它被就地改写
|
||||
const draft = [row({ b_canuse: 0, b_prefix: 'A' })]
|
||||
const wrapper = mountPanel(draft)
|
||||
|
||||
wrapper.findComponent(G3Switch).vm.$emit('update:modelValue', true)
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
// 已落草稿:直接改这一行的属性(父级 ref 是深度响应式,改得见)
|
||||
expect(wrapper.emitted('update:autocode')).toBeUndefined()
|
||||
expect(draft[0]?.b_canuse).toBe(1)
|
||||
expect(draft[0]?.b_prefix).toBe('A') // 沿用原行,未被占位行覆盖
|
||||
})
|
||||
|
||||
it('紧凑网格固定竖排且标签左对齐,不跟随全局横排配置', () => {
|
||||
const wrapper = mountPanel()
|
||||
expect(wrapper.find('form').classes()).toContain('g3-form--vertical')
|
||||
// 标签左对齐依赖 G3Form 的默认 labelAlign=left;竖排下若回到 right 会被推到整列右边缘
|
||||
expect(wrapper.findAll('.g3-form-item__label.is-label-right')).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('预览按 前缀 + 日期 + 补位流水号 拼接', async () => {
|
||||
const wrapper = mountPanel([
|
||||
row({ b_prefix: 'G3', b_dateformat: '', b_seqwidth: 4, b_resettype: 'none' }),
|
||||
])
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
const preview = wrapper.find('[data-field="b_preview"] input')
|
||||
expect(preview.attributes('readonly')).toBeDefined()
|
||||
expect((preview.element as HTMLInputElement).value).toBe('G3-0001')
|
||||
})
|
||||
|
||||
it('启用态下的合法规则校验通过', async () => {
|
||||
const wrapper = mountPanel([row()])
|
||||
|
||||
expect(await wrapper.vm.validate()).toEqual([])
|
||||
})
|
||||
|
||||
it('启用但未选业务编号字段时报错(错误挂在对应 FormItem 上)', async () => {
|
||||
const wrapper = mountPanel([row({ b_field: null })])
|
||||
|
||||
const errors = await wrapper.vm.validate()
|
||||
expect(errors.map((item) => item.name)).toContain('b_field')
|
||||
expect(errors.find((item) => item.name === 'b_field')?.errors[0]).toBe('请选择业务编号字段')
|
||||
})
|
||||
|
||||
it('位数超出 1-18 时报错', async () => {
|
||||
const wrapper = mountPanel([row({ b_seqwidth: 20 })])
|
||||
|
||||
const errors = await wrapper.vm.validate()
|
||||
expect(errors.find((item) => item.name === 'b_seqwidth')?.errors[0]).toBe(
|
||||
'流水号位数必须是 1 到 18 之间的整数',
|
||||
)
|
||||
})
|
||||
|
||||
it('未启用时不校验(占位行只用于展示)', async () => {
|
||||
const wrapper = mountPanel()
|
||||
|
||||
expect(await wrapper.vm.validate()).toEqual([])
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user