Files
workspace/code/fms/fms-vue/tests/unit/module-dirty-sections.spec.js
T
oneao 6bfa0d816f feat(module-management): 导航状态化阶段二——表单设计「缺 N」徽标
- 复用既有 missingConfigCount 通用口径,新增 missingEditCount(启用字段
  未被 editConfig 任何行 b_field_id 引用的数量),子表表格编辑方式下同样成立
- configGroups 表单设计项挂「缺 N」徽标,样式与语义沿用查询配置;
  拖入画布后徽标消失
- spec 新增 4 用例:缺配计数、停用字段不计、b_field_id 类型不一致按字符串比较、空态为 0
2026-08-30 20:07:56 +08:00

176 lines
6.8 KiB
JavaScript
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.
/**
* 分 section 脏检查测试:守护 hasModuleChanges 的判定语义。
* 背景见 docs/module-management-tab-status-plan.md 阶段一:
* - 加载时自动补全的默认列表行只写 drafts 不写 originals(useModuleConfig.loadModuleConfig),
* 此时视为「脏」是既有行为,分 section 对比必须原样保留,不得“修复”;
* - hasModuleChanges 从整树 JSON.stringify 对比改为 dirtySections 派生,
* 本 spec 以判定结果等价为验收基准。
*/
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { ref } from 'vue'
import { useModuleConfig } from '@/views/system/module-management/composables/useModuleConfig'
vi.mock('@/services/api', () => ({
loadDataApi: vi.fn(),
describeApi: vi.fn(),
}))
vi.mock('@/components/ui', () => ({
Message: { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() },
}))
beforeEach(() => {
vi.clearAllMocks()
})
/** 完整的 8 段草稿结构(与 loadModuleConfig 构造的 original 同形) */
function baseConfig(over = {}) {
const config = {
module: { b_id: '1', b_code: 'demo', b_name: '演示模块', b_module_type: 'data' },
fields: [{ b_id: '10', b_field: 'amount', b_name: '金额', b_canuse: 1 }],
groups: [],
listConfig: [],
editConfig: [],
queryConfig: [],
autoCode: [],
powers: [],
}
return Object.assign(config, over)
}
function setup({ drafts, originals }) {
const draftsRef = ref(drafts)
const originalsRef = ref(originals)
const deps = {
moduleSelectedId: ref('1'),
moduleTreeData: ref([]),
findModuleNode: () => null,
selectedModule: ref({ b_id: '1', b_code: 'demo', b_name: '演示模块' }),
busy: ref(false),
configLoading: ref(false),
configSyncing: ref(false),
activeSection: ref('basic'),
loadedModuleId: ref('1'),
originals: originalsRef,
drafts: draftsRef,
skipModuleLoad: { value: false },
showConfirm: vi.fn(),
switchConfirm: ref(null),
i18nPanelRef: ref(null),
}
return { ...useModuleConfig(deps), originalsRef, draftsRef }
}
describe('useModuleConfig 脏检查', () => {
it('未修改时 hasModuleChanges 为 false', () => {
const originals = baseConfig()
const { hasModuleChanges } = setup({ drafts: JSON.parse(JSON.stringify(originals)), originals })
expect(hasModuleChanges.value).toBe(false)
})
it('无草稿时 hasModuleChanges 为 false', () => {
const { hasModuleChanges } = setup({ drafts: null, originals: null })
expect(hasModuleChanges.value).toBe(false)
})
it('任一 section 修改即 hasModuleChanges 为 true', () => {
const originals = baseConfig()
for (const key of ['module', 'fields', 'groups', 'listConfig', 'editConfig', 'queryConfig', 'autoCode', 'powers']) {
const drafts = JSON.parse(JSON.stringify(originals))
if (key === 'module') drafts.module.b_name = '改名'
else drafts[key] = [...drafts[key], { b_id: 'new' }]
const { hasModuleChanges } = setup({ drafts, originals })
expect(hasModuleChanges.value, `修改 ${key} 应判定为脏`).toBe(true)
}
})
it('加载时补全的默认列表行(只写 drafts)视为脏——既有行为', () => {
const originals = baseConfig()
const drafts = JSON.parse(JSON.stringify(originals))
drafts.listConfig = [{ b_id: 'tmp1', b_field_id: '10', b_visible: 1, b_xh: 10 }]
const { hasModuleChanges } = setup({ drafts, originals })
expect(hasModuleChanges.value).toBe(true)
})
it('查询模块缺失的 section(undefined)两侧一致时不脏,单侧出现即脏', () => {
const originals = {
module: { b_id: '2', b_code: 'q', b_module_type: 'query' },
fields: [],
groups: [],
listConfig: [],
editConfig: undefined,
queryConfig: [],
autoCode: undefined,
powers: [],
}
const same = setup({ drafts: JSON.parse(JSON.stringify(originals)), originals })
expect(same.hasModuleChanges.value).toBe(false)
const drafts = JSON.parse(JSON.stringify(originals))
drafts.editConfig = []
const diff = setup({ drafts, originals })
expect(diff.hasModuleChanges.value).toBe(true)
})
it('dirtySections 精确指出被修改的 section', () => {
const originals = baseConfig()
const drafts = JSON.parse(JSON.stringify(originals))
drafts.module.b_name = '改名'
drafts.queryConfig = [{ b_id: 'q1' }]
const { dirtySections } = setup({ drafts, originals })
expect(dirtySections.value.has('module')).toBe(true)
expect(dirtySections.value.has('queryConfig')).toBe(true)
expect(dirtySections.value.has('fields')).toBe(false)
expect(dirtySections.value.size).toBe(2)
})
it('保存后整体替换 originals/drafts 为同一份深拷贝,脏状态清空', () => {
const originals = baseConfig()
const drafts = JSON.parse(JSON.stringify(originals))
drafts.module.b_name = '改名'
const api = setup({ drafts, originals })
expect(api.hasModuleChanges.value).toBe(true)
// 模拟 useModuleSave 保存后的整体 cloneData 换引用
const saved = JSON.parse(JSON.stringify(drafts))
api.originalsRef.value = saved
api.draftsRef.value = JSON.parse(JSON.stringify(saved))
expect(api.hasModuleChanges.value).toBe(false)
})
})
describe('useModuleConfig 缺配统计(表单设计徽标)', () => {
function configWith(fields, editConfig) {
return { module: { b_id: '1', b_module_type: 'data' }, fields, groups: [], listConfig: [], editConfig, queryConfig: [], autoCode: [], powers: [] }
}
it('启用字段未被 editConfig 引用即计入缺配', () => {
const fields = [
{ b_id: '10', b_field: 'a', b_canuse: 1 },
{ b_id: '11', b_field: 'b', b_canuse: 1 },
]
const editConfig = [{ b_id: 'e1', b_field_id: '10' }]
const { missingEditCount } = setup({ drafts: configWith(fields, editConfig), originals: configWith(fields, editConfig) })
expect(missingEditCount.value).toBe(1)
})
it('停用字段不计入缺配', () => {
const fields = [
{ b_id: '10', b_field: 'a', b_canuse: 1 },
{ b_id: '11', b_field: 'b', b_canuse: 0 },
]
const { missingEditCount } = setup({ drafts: configWith(fields, []), originals: configWith(fields, []) })
expect(missingEditCount.value).toBe(1)
})
it('b_field_id 与 b_id 类型不一致(数字/字符串)仍按字符串比较', () => {
const fields = [{ b_id: 10, b_field: 'a', b_canuse: 1 }]
const editConfig = [{ b_id: 'e1', b_field_id: '10' }]
const { missingEditCount } = setup({ drafts: configWith(fields, editConfig), originals: configWith(fields, editConfig) })
expect(missingEditCount.value).toBe(0)
})
it('无字段时缺配为 0(新建模块空态不显示徽标)', () => {
const { missingEditCount } = setup({ drafts: configWith([], []), originals: configWith([], []) })
expect(missingEditCount.value).toBe(0)
})
})