Files
workspace/code/fms/fms-vue/tests/views/menu-unsaved-node-switch.spec.js
T
2026-09-14 17:28:20 +08:00

84 lines
3.1 KiB
JavaScript

/**
* 回归用例:菜单管理 - 新建节点(未保存)→ 切到旧节点 → 切回新节点。
* 曾因 loadMenuConfig 用临时 id 查库返回空 → maindata 为 null →
* 模板以 null menu 渲染 → render 抛错 → 在布局 <Transition> 下崩溃
* (表现为 "Component inside <Transition> renders non-element root node" +
* "Cannot set properties of null (setting '__vnode')")。
* 修复:watch(menuSelectedId) 对未落库节点不走 loadMenuConfig,从树节点重建草稿。
*
* 临时 id 现由 createTempId() 生成本地负数(不再取号),断言按实际值 -1 校验。
*/
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { flushPromises } from '@vue/test-utils'
import MenuManagement from '@/views/module/menu-management/index.vue'
import { mountPage } from '../helpers/app.js'
vi.mock('@/services/api', () => ({
loadDataApi: vi.fn(),
saveObjectApi: vi.fn(() => Promise.resolve({ code: 0, success: true })),
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 } from '@/services/api'
const savedMenu = {
b_id: '1',
b_code: 'home',
b_parent_id: null,
b_depth: 0,
b_path: '/1/',
b_name: '首页',
b_menu_type: 'page',
b_route: '/dashboard',
b_xh: 10,
b_canuse: 1,
}
beforeEach(() => {
loadDataApi.mockReset()
loadDataApi.mockImplementation((view, where) => {
if (view === 's_menu' && where === '1 = 1') return Promise.resolve({ data: [savedMenu] })
// 加载单行用 sqlText 拼的 N'1' 字面量
if (view === 's_menu' && where === "b_id = N'1'")
return Promise.resolve({ data: [savedMenu] })
if (view === 's_menu') return Promise.resolve({ data: [] }) // 含本地临时 id(负数):查无此行
return Promise.resolve({ data: [] })
})
})
describe('菜单管理:未保存新节点来回切换', () => {
it('切回未保存的新节点时,从树节点重建草稿,不查库、渲染不报错', async () => {
const { wrapper } = await mountPage(MenuManagement)
await flushPromises()
// 1. 新建节点(未保存)
await wrapper.vm.addMenu(null, 'page')
await flushPromises()
expect(String(wrapper.vm.menuSelectedId)).toBe('-1')
expect(wrapper.vm.maindata?.b_menu_type).toBe('page')
// 2. 切到旧节点(已保存)
wrapper.vm.menuSelectedId = '1'
await flushPromises()
expect(wrapper.vm.maindata?.b_id).toBe('1')
// 3. 切回新节点:不应对临时 id 发起查库请求
loadDataApi.mockClear()
wrapper.vm.menuSelectedId = '-1'
await flushPromises()
await flushPromises()
expect(loadDataApi).not.toHaveBeenCalled()
expect(wrapper.vm.maindata).not.toBeNull()
expect(String(wrapper.vm.maindata?.b_id)).toBe('-1')
expect(wrapper.vm.maindata?.b_menu_type).toBe('page')
expect(String(wrapper.vm.loadedMenuId)).toBe('-1')
})
})