Files
workspace/code/fms/fms-vue/tests/views/module-unsaved-after-save.spec.js
T
2026-09-27 21:59:13 +08:00

703 lines
24 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.
/**
* 回归用例:模块管理 - 修改基础信息 → 保存 → 切到其它树节点仍提示「未保存」。
*
* 成因:查询配置面板(ModuleQueryConfigPanel)的「行草稿 → query JSON」回写在配置
* 重载时被触发。保存走 afterSave → loadModuleConfig(同一模块重载,面板不卸载),
* schema ref 被换成新对象 → 面板重新解析出行草稿 → 回写监听发现
* rowsToQuerySchema(rows) 与当前 schema 文本不等(补齐 quick/groups、给条件补默认
* component 等「规范化」差异),于是把规范化后的 query JSON 写回草稿:
* - 草稿与库中基线文本不一致 → hasUnsavedChanges() 恒为真,切节点必弹确认框;
* - 编辑器未建模的属性(运行时「保存为通用」写入的 condition.area 等)被静默改写。
* 修复:回写前先与「当前配置的规范化结果」比较,仅用户真实改动才回写
* (与 TableDesignEditor / FormDesignEditor 的回写策略一致)。
*/
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import ModuleManagement from '@/views/module/module-management/index.vue'
import { createTestPinia, createTestRouter } from '../helpers/app.js'
import { createDefaultSchema, schemaToJsonText } from '@/utils/schemaJson'
vi.mock('@/services/api', () => ({
loadDataApi: vi.fn(),
saveObjectApi: vi.fn(),
nextIdApi: vi.fn(() => Promise.resolve({ data: 9001, code: 0, success: true })),
describeApi: vi.fn(() => Promise.resolve({ data: [], code: 0, success: true })),
}))
vi.mock('@/components/ui/message/message-manager.js', () => {
const m = { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() }
return { Message: m, default: m }
})
import { loadDataApi, saveObjectApi } from '@/services/api'
import { Message } from '@/components/ui/message/message-manager.js'
/** 库中的一条关系:demo.b_name → other.b_name(一对多,源侧即当前模块) */
function relationRow() {
return {
b_source_module_id: 'demo',
b_source_field: 'b_name',
b_target_module_id: 'other',
b_target_field: 'b_name',
b_relation_type: 'one_to_many',
b_on_delete: 'none',
b_canuse: 1,
b_xh: 10,
}
}
function moduleRow(id, name) {
return {
b_id: id,
b_parent_id: null,
b_depth: 0,
b_path: `/${id}/`,
b_name: name,
b_i18n: `module.${id}`,
b_module_type: 'data',
b_view_table: `v_${id}`,
b_save_table: `t_${id}`,
b_key_field: 'b_id',
b_order_sql: null,
b_query_sql: null,
b_config_json: null,
b_canuse: 1,
b_xh: 10,
b_bz: null,
// 迁移后 s_module 才有这一列(见 sql/fms_module_updated_at.sql)
b_updated_at: '2026-09-01 08:00:00',
}
}
/** 库中历史查询配置:缺 quick 键、条件未显式写 component,且带运行时写入的 area 标记 */
const legacyQuerySchema = {
schemaVersion: 1,
groups: {
logic: 'and',
conditions: [{ field: 'b_name', operator: 'like', area: 'hidden' }],
},
}
function schemaRow(moduleId, type, json) {
return {
b_module_id: moduleId,
b_schema_type: type,
b_schema_json: schemaToJsonText(type, json),
b_canuse: 1,
}
}
let db
let savedRequests
function buildDb() {
const fields = ['demo', 'other'].map((id) => ({
b_module_id: id,
b_field: 'b_name',
b_name: '名称',
b_i18n: `field.${id}.b_name`,
b_xh: 10,
b_canuse: 1,
}))
const schemas = [
schemaRow('demo', 'view', createDefaultSchema('view')),
schemaRow('demo', 'edit', createDefaultSchema('edit')),
schemaRow('demo', 'query', { schemaVersion: 1, groups: [legacyQuerySchema.groups] }),
]
return {
s_module: [moduleRow('demo', '示例模块'), moduleRow('other', '另一个模块')],
s_field: fields,
s_module_schema: schemas,
s_autocode: [],
s_power: [],
s_relation: [],
s_delete_rule: [],
s_i18n: [{ b_key: 'module.demo', b_locale: 'en-US', b_value: 'Demo module' }],
}
}
const rowsOf = (view) => (db[view] || []).map((row) => ({ ...row }))
beforeEach(() => {
db = buildDb()
savedRequests = []
loadDataApi.mockReset()
loadDataApi.mockImplementation((view, condition) => {
if (view === 's_i18n_type')
return Promise.resolve({
data: [
{ b_id: 'zh-CN', b_name: '简体中文', b_default: 1 },
{ b_id: 'en-US', b_name: 'English', b_default: 0 },
],
})
return Promise.resolve({ data: rowsOf(view) })
})
saveObjectApi.mockReset()
saveObjectApi.mockImplementation((requests) => {
savedRequests.push(...(requests || []))
for (const request of requests || []) {
const table = request.table
if (!db[table]) continue
for (const row of request.updates || []) {
const keyFields = String(request.key_field || 'b_id').split(',')
const target = db[table].find((item) =>
keyFields.every((field) => String(item[field]) === String(row[field])),
)
if (target) Object.assign(target, row)
}
for (const row of request.inserts || []) db[table].push({ ...row })
}
return Promise.resolve({ code: 0, success: true })
})
})
/**
* 保存后的重载(afterSave → loadModuleConfig)不是 await 的,断言前先等它把新基线装载完,
* 避免并发跑用例时时序抖动
*/
async function settleConfigReload(wrapper) {
for (let i = 0; i < 50 && wrapper.vm.configLoading; i += 1) {
await flushPromises()
}
await flushPromises()
}
async function mountManagement() {
const pinia = createTestPinia()
const router = createTestRouter('/')
await router.isReady()
return mount(ModuleManagement, { global: { plugins: [pinia, router] } })
}
describe('模块管理:保存后的未保存判定', () => {
it('保存基础信息后不应再判定为未保存,切换树节点不再弹确认框', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
// 打开即干净:加载时的配置规范化不得算作改动
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
wrapper.vm.maindata.b_name = '改名后'
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
expect(wrapper.vm.maindata.b_name).toBe('改名后')
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
// 切到其它节点:直接切换,不弹「未保存」确认框
wrapper.vm.onModuleSelect('other')
await flushPromises()
expect(wrapper.vm.switchConfirm).toBe(null)
expect(String(wrapper.vm.moduleSelectedId)).toBe('other')
})
it('未被用户编辑的查询配置不应随保存写回(不静默改写 area 等属性)', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.maindata.b_name = '改名后'
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
// 只提交主表变更;查询配置(s_module_schema.query)不参与
expect(savedRequests.some((request) => request.table === 's_module')).toBe(true)
expect(savedRequests.some((request) => request.table === 's_module_schema')).toBe(false)
// 库中 query JSON 保持原样(含 area 标记)
const queryRow = db.s_module_schema.find((row) => row.b_schema_type === 'query')
expect(JSON.parse(queryRow.b_schema_json).groups[0].conditions[0].area).toBe('hidden')
// 草稿里的查询配置也不得被「规范化」改写(否则下一次保存就会把它落库)
expect(wrapper.vm.schemaCurrent.query.value).toEqual({
schemaVersion: 1,
groups: [
{ logic: 'and', conditions: [{ field: 'b_name', operator: 'like', area: 'hidden' }] },
],
})
})
it('多语言的人工翻译应计入未保存,保存后不再提示', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
const row = wrapper.vm.i18n.find((item) => item.b_key === 'module.demo')
expect(row, '库中的模块名多语言行应加载到草稿').toBeTruthy()
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
row['en-US'] = 'Demo module v2'
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
expect(
db.s_i18n.find((item) => item.b_key === 'module.demo' && item.b_locale === 'en-US')?.b_value,
).toBe('Demo module v2')
})
it('权限面板:库中历史派生列不算未保存改动,仅在保存前物化', async () => {
db.s_power = [
{
b_id: 'module.demo.access',
b_object_type: 'module',
b_object_id: 'demo',
b_action: 'access',
b_type: 'action',
b_name: '模块使用',
b_canuse: 1,
b_xh: 100,
},
]
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
// 打开即干净:加载阶段不得把库里的派生列改写进草稿
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
expect(wrapper.vm.powers[0].b_id).toBe('module.demo.access')
expect(wrapper.vm.powers[0].b_xh).toBe(100)
wrapper.vm.powers[0].b_action = 'audit'
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
const powerReq = savedRequests.find((request) => request.table === 's_power')
expect(powerReq, '动作变化应提交权限点变更').toBeTruthy()
// 权限编码即主键:动作变化会换编码,落库表现为「删旧码 + 插新码」
expect(powerReq.deletes).toEqual([{ b_id: 'module.demo.access' }])
expect(powerReq.inserts[0]).toMatchObject({
b_id: 'action.demo.audit',
b_object_type: 'module',
b_object_id: 'demo',
b_type: 'action',
b_xh: 10,
})
})
it('保存当前模块不得丢弃其它未保存的新建草稿节点', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
await wrapper.vm.addModule(null, 'module')
await flushPromises()
const draftId = String(wrapper.vm.moduleSelectedId)
expect(draftId.startsWith('-'), '新建模块用本地临时负数 id 占位').toBe(true)
wrapper.vm.onModuleSelect('demo')
await flushPromises()
await flushPromises()
expect(String(wrapper.vm.moduleSelectedId)).toBe('demo')
wrapper.vm.maindata.b_name = '改名后'
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
expect(wrapper.vm.unsavedModuleIds.has(draftId), '草稿仍应标记为未保存').toBe(true)
expect(
wrapper.vm.moduleTreeData.find((node) => String(node.b_id) === draftId),
'草稿节点应保留在树中',
).toBeTruthy()
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('删除其它节点不得丢掉当前未保存的草稿', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.maindata.b_name = '改名后'
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
wrapper.vm.deleteModule('other')
await flushPromises()
await wrapper.vm.onConfirmOk()
await flushPromises()
expect(String(wrapper.vm.moduleSelectedId)).toBe('demo')
expect(wrapper.vm.maindata.b_name).toBe('改名后')
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
})
it('父模块尚未保存时不允许先保存子模块(避免插入指向临时 id 的孤儿行)', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
await wrapper.vm.addModule(null, 'module')
await flushPromises()
const parentDraftId = String(wrapper.vm.moduleSelectedId)
await wrapper.vm.addModule(parentDraftId, 'module')
await flushPromises()
wrapper.vm.maindata.b_id = 'sub_module'
wrapper.vm.maindata.b_name = '子模块'
const ok = await wrapper.vm.handleSave()
await flushPromises()
expect(ok).toBe(false)
expect(Message.warning).toHaveBeenCalledWith('父模块尚未保存,请先保存父模块')
expect(savedRequests).toEqual([])
})
it('删除模块应一并清理菜单绑定(s_menu_module)', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.deleteModule('demo')
await flushPromises()
expect(wrapper.vm.confirmVisible).toBe(true)
await wrapper.vm.onConfirmOk()
await flushPromises()
const menuReq = savedRequests.find((request) => request.table === 's_menu_module')
expect(menuReq, '模块删除必须清理 s_menu_module 绑定行').toBeTruthy()
expect(menuReq.key_field).toBe('b_module_id')
expect(menuReq.deletes).toEqual([{ b_module_id: 'demo' }])
expect(
savedRequests.some(
(request) => request.table === 's_module' && request.deletes?.[0]?.b_id === 'demo',
),
).toBe(true)
})
it('模块关联:加载拆分源/目标两侧,保存只提交源侧行(四列复合主键)', async () => {
db.s_relation = [
{
b_source_module_id: 'demo',
b_source_field: 'b_name',
b_target_module_id: 'other',
b_target_field: 'b_name',
b_relation_type: 'one_to_many',
b_canuse: 1,
b_xh: 10,
},
{
b_source_module_id: 'other',
b_source_field: 'b_name',
b_target_module_id: 'demo',
b_target_field: 'b_name',
b_relation_type: 'many_to_one',
b_canuse: 1,
b_xh: 20,
},
]
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
// 源侧进可编辑草稿,目标侧只读展示;打开即干净(本地行键不得算作改动)
expect(wrapper.vm.relations).toHaveLength(1)
expect(wrapper.vm.reverseRelations).toHaveLength(1)
expect(String(wrapper.vm.reverseRelations[0].b_source_module_id)).toBe('other')
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
wrapper.vm.relations[0].b_canuse = 0
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
const relationReq = savedRequests.find((request) => request.table === 's_relation')
expect(relationReq, '关联变更应提交 s_relation').toBeTruthy()
expect(relationReq.key_field).toBe(
'b_source_module_id,b_source_field,b_target_module_id,b_target_field',
)
expect(relationReq.updates).toEqual([
{
b_source_module_id: 'demo',
b_source_field: 'b_name',
b_target_module_id: 'other',
b_target_field: 'b_name',
b_relation_type: 'one_to_many',
b_canuse: 0,
b_xh: 10,
},
])
// 反向行不属于本模块草稿,保存不得把它算作删除
expect(relationReq.deletes ?? []).toEqual([])
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('删除模块应一并清理双向模块关联(s_relation)', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.deleteModule('demo')
await flushPromises()
await wrapper.vm.onConfirmOk()
await flushPromises()
const relationReqs = savedRequests.filter((request) => request.table === 's_relation')
expect(relationReqs).toHaveLength(2)
expect(relationReqs).toEqual([
{
table: 's_relation',
key_field: 'b_source_module_id',
deletes: [{ b_source_module_id: 'demo' }],
},
{
table: 's_relation',
key_field: 'b_target_module_id',
deletes: [{ b_target_module_id: 'demo' }],
},
])
})
it('删除 SQL 规则:加载不脏,只提交变更(雪花主键)', async () => {
db.s_relation = [relationRow()]
db.s_delete_rule = [
{
b_id: '1900000000000000001',
b_module_id: 'demo',
b_sql: 'select b_id from demo where b_id in (:ids) and b_name like N\'a\'',
b_message: '示例模块记录已锁定,不能删除',
b_canuse: 1,
b_xh: 10,
},
]
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
// 规则进 rules;打开即干净
expect(wrapper.vm.rules).toHaveLength(1)
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
wrapper.vm.rules[0].b_canuse = 0
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
const ruleReq = savedRequests.find((request) => request.table === 's_delete_rule')
expect(ruleReq, '规则变更应提交 s_delete_rule').toBeTruthy()
expect(ruleReq.key_field).toBe('b_id')
expect(ruleReq.updates?.[0]).toMatchObject({
b_id: '1900000000000000001',
b_module_id: 'demo',
b_canuse: 0,
})
// 关系未变:不产生 s_relation 请求
expect(savedRequests.some((request) => request.table === 's_relation')).toBe(false)
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('关联删除处理:改 b_on_delete 随 s_relation 一起提交,不产生规则行', async () => {
db.s_relation = [relationRow()]
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
expect(wrapper.vm.rules).toEqual([])
wrapper.vm.relations[0].b_on_delete = 'cascade'
expect(wrapper.vm.hasUnsavedChanges()).toBe(true)
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
const relationReq = savedRequests.find((request) => request.table === 's_relation')
expect(relationReq?.updates?.[0]).toMatchObject({ b_on_delete: 'cascade' })
// 关联处置收敛到 s_relation,不再生成任何规则表请求
expect(savedRequests.some((request) => request.table === 's_delete_rule')).toBe(false)
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('删除模块应一并清理删除 SQL 规则(s_delete_rule)', async () => {
db.s_relation = [relationRow()]
db.s_delete_rule = [
{
b_id: '1900000000000000001',
b_module_id: 'demo',
b_sql: 'select 1 as b_id',
b_message: '不能删除',
},
{
b_id: '1900000000000000002',
b_module_id: 'other',
b_sql: 'select 1 as b_id',
b_message: '不能删除',
},
]
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.deleteModule('demo')
await flushPromises()
await wrapper.vm.onConfirmOk()
await flushPromises()
const ruleReqs = savedRequests.filter((request) => request.table === 's_delete_rule')
const moduleReq = ruleReqs.find((request) => request.deletes?.[0]?.b_module_id === 'demo')
expect(moduleReq?.deletes).toEqual([{ b_module_id: 'demo' }])
// 只按模块列清理,不误伤其他模块的规则
expect(ruleReqs.every((request) => request.deletes.every((row) => row.b_module_id === 'demo'))).toBe(
true,
)
})
})
describe('模块管理:卡头信息与刷新', () => {
it('保存主表变更时前端不提交审计列,草稿也不会因此变脏', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.maindata.b_name = '改名后'
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
const moduleReq = savedRequests.find((request) => request.table === 's_module')
expect(moduleReq.updates?.[0]).toMatchObject({ b_id: 'demo', b_name: '改名后' })
// 审计列(b_updated_at 等)由后端按表列存在性统一维护(核心表结构设计 §1.6)
expect(moduleReq.updates?.[0]).not.toHaveProperty('b_updated_at')
expect(moduleReq.updates?.[0]).not.toHaveProperty('b_updated_by')
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('只改子表(多语言)时也触碰主表行,让后端刷新「最后保存时间」', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
const row = wrapper.vm.i18n.find((item) => item.b_key === 'module.demo')
row['en-US'] = 'Demo module v2'
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
// 主表行本身没有变化:补一条只带主键的 update 触碰它,时间戳由后端补
const moduleReq = savedRequests.find((request) => request.table === 's_module')
expect(moduleReq.updates).toEqual([{ b_id: 'demo' }])
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('库里还没有 b_updated_at 列时(迁移未执行)不触碰主表行', async () => {
delete db.s_module.find((item) => item.b_id === 'demo').b_updated_at
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
const row = wrapper.vm.i18n.find((item) => item.b_key === 'module.demo')
row['en-US'] = 'Demo module v2'
await wrapper.vm.handleSave()
await settleConfigReload(wrapper)
// 只带主键的 update 在后端补不上任何可写列(审计列不存在),会被「没有可修改的字段」拒绝
expect(savedRequests.some((request) => request.table === 's_module')).toBe(false)
})
it('刷新:有未保存草稿时先弹确认,放弃后原地重载并丢弃草稿', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.maindata.b_name = '改名后'
wrapper.vm.requestReloadConfig()
await flushPromises()
expect(wrapper.vm.switchConfirm).toMatchObject({ pendingId: 'demo', reload: true })
await wrapper.vm.onSwitchDiscard()
await settleConfigReload(wrapper)
expect(String(wrapper.vm.moduleSelectedId)).toBe('demo')
expect(wrapper.vm.maindata.b_name).toBe('示例模块')
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('刷新:确认框选「保存并刷新」时保存后原地重载,不切换目标', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.maindata.b_name = '改名后'
wrapper.vm.requestReloadConfig()
await flushPromises()
await wrapper.vm.onSwitchSave()
await settleConfigReload(wrapper)
expect(wrapper.vm.switchConfirm).toBe(null)
expect(String(wrapper.vm.moduleSelectedId)).toBe('demo')
expect(wrapper.vm.maindata.b_name).toBe('改名后')
expect(wrapper.vm.hasUnsavedChanges()).toBe(false)
})
it('刷新:无未保存改动时直接重载,不弹确认框', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
loadDataApi.mockClear()
wrapper.vm.requestReloadConfig()
await settleConfigReload(wrapper)
expect(wrapper.vm.switchConfirm).toBe(null)
expect(loadDataApi).toHaveBeenCalledWith('s_module', "b_id = N'demo'")
})
it('卡头「更多」删除模块走与树右键相同的入口', async () => {
const wrapper = await mountManagement()
await flushPromises()
wrapper.vm.moduleSelectedId = 'demo'
await flushPromises()
await flushPromises()
wrapper.vm.onMoreAction({ key: 'delete' })
await flushPromises()
expect(wrapper.vm.confirmVisible).toBe(true)
expect(wrapper.vm.confirmState?.title).toBe('删除模块')
})
})