Files
workspace/code/fms/fms-vue/tests/unit/module-dirty-sections.spec.js
T
oneao 08646c547f revert(module-management): 撤回表单设计「缺 N」徽标(阶段二)
并非所有启用字段都应出现在表单里(审计字段等常有意不布局),
「缺 N」口径对表单设计是假警报。revert 6bfa0d81,计划文档记录决策。
阶段一(tab 脏点)保留;查询配置的「缺 N」为使用者既有实现,不动。
2026-08-30 20:23:04 +08:00

139 lines
5.2 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)
})
})