180 lines
5.3 KiB
JavaScript
180 lines
5.3 KiB
JavaScript
/**
|
|
* 其他数据页:左侧模块树的子树裁剪。
|
|
*
|
|
* 本页只显示挂在根模块 `base_otherdata` 之下的子孙,不显示 s_module 里的其他模块。
|
|
* 这段裁剪原先按 b_path 前缀匹配实现,现已统一到 @/utils/tree 的 collectDescendantIds
|
|
* (按 b_parent_id 展开)—— 与同一函数里向上回溯祖先所用的权威字段保持一致。
|
|
* 用例按「行为」而非「实现」编写,因此两种实现都应通过。
|
|
*/
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { flushPromises } from '@vue/test-utils'
|
|
import Otherdata from '@/views/base/otherdata/index.vue'
|
|
import { mountPage } from '../helpers/app.js'
|
|
|
|
vi.mock('@/services/api', () => ({
|
|
loadDataApi: vi.fn(),
|
|
pageDataApi: vi.fn(() => Promise.resolve({ data: { rows: [], total: 0 } })),
|
|
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('@/stores/permissions', () => ({
|
|
usePermissionStore: () => ({
|
|
load: () => Promise.resolve(),
|
|
canAccess: () => true,
|
|
canPower: () => true,
|
|
}),
|
|
}))
|
|
|
|
import { loadDataApi } from '@/services/api'
|
|
|
|
/** 造一条 s_module 行;默认启用、非 virtual */
|
|
function makeModule(over = {}) {
|
|
return {
|
|
b_id: 'x',
|
|
b_parent_id: null,
|
|
b_depth: 0,
|
|
b_path: '/x/',
|
|
b_name: 'X',
|
|
b_module_type: 'data',
|
|
b_xh: 10,
|
|
b_canuse: 1,
|
|
...over,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 固定夹具:
|
|
* base_otherdata(根)
|
|
* ├─ odc_1(分类)
|
|
* │ └─ od_1(数据模块)
|
|
* └─ od_2(数据模块)
|
|
* other_root(完全无关的模块,不应出现在本页)
|
|
*/
|
|
const FIXTURE = [
|
|
makeModule({
|
|
b_id: 'base_otherdata',
|
|
b_parent_id: null,
|
|
b_depth: 0,
|
|
b_path: '/base_otherdata/',
|
|
b_module_type: 'module',
|
|
}),
|
|
makeModule({
|
|
b_id: 'odc_1',
|
|
b_parent_id: 'base_otherdata',
|
|
b_depth: 1,
|
|
b_path: '/base_otherdata/odc_1/',
|
|
b_module_type: 'module',
|
|
}),
|
|
makeModule({
|
|
b_id: 'od_1',
|
|
b_parent_id: 'odc_1',
|
|
b_depth: 2,
|
|
b_path: '/base_otherdata/odc_1/od_1/',
|
|
b_module_type: 'data',
|
|
}),
|
|
makeModule({
|
|
b_id: 'od_2',
|
|
b_parent_id: 'base_otherdata',
|
|
b_depth: 1,
|
|
b_path: '/base_otherdata/od_2/',
|
|
b_module_type: 'data',
|
|
}),
|
|
makeModule({
|
|
b_id: 'other_root',
|
|
b_parent_id: null,
|
|
b_depth: 0,
|
|
b_path: '/other_root/',
|
|
b_module_type: 'module',
|
|
}),
|
|
]
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear()
|
|
sessionStorage.clear()
|
|
loadDataApi.mockReset()
|
|
loadDataApi.mockImplementation(() =>
|
|
Promise.resolve({ data: FIXTURE.map((row) => ({ ...row })) }),
|
|
)
|
|
})
|
|
|
|
async function mountOtherdata() {
|
|
const { wrapper } = await mountPage(Otherdata)
|
|
await flushPromises()
|
|
return wrapper
|
|
}
|
|
|
|
describe('其他数据:只显示根模块之下的子孙', () => {
|
|
it('包含根的各层级子孙,排除根自身', async () => {
|
|
const wrapper = await mountOtherdata()
|
|
const ids = wrapper.vm.modules.map((item) => String(item.b_id)).toSorted()
|
|
|
|
// 根自身不进树(它是本页入口,不是可导航节点)
|
|
expect(ids).toEqual(['od_1', 'od_2', 'odc_1'])
|
|
})
|
|
|
|
it('排除与根无关的其他模块', async () => {
|
|
const wrapper = await mountOtherdata()
|
|
const ids = wrapper.vm.modules.map((item) => String(item.b_id))
|
|
|
|
expect(ids).not.toContain('other_root')
|
|
})
|
|
|
|
it('virtual 类型即使挂在根下也不进树', async () => {
|
|
loadDataApi.mockImplementation(() =>
|
|
Promise.resolve({
|
|
data: [
|
|
...FIXTURE.map((row) => ({ ...row })),
|
|
makeModule({
|
|
b_id: 'od_virtual',
|
|
b_parent_id: 'base_otherdata',
|
|
b_depth: 1,
|
|
b_path: '/base_otherdata/od_virtual/',
|
|
b_module_type: 'virtual',
|
|
}),
|
|
],
|
|
}),
|
|
)
|
|
|
|
const wrapper = await mountOtherdata()
|
|
const ids = wrapper.vm.modules.map((item) => String(item.b_id))
|
|
|
|
expect(ids).not.toContain('od_virtual')
|
|
})
|
|
|
|
it('b_path 与 b_parent_id 不一致时以 b_parent_id 为准(b_path 只是派生字段)', async () => {
|
|
// 回归用例:裁剪原先按 b_path 前缀匹配,而同一函数里向上回溯祖先用 b_parent_id。
|
|
// 这条数据的 b_path 是过期的(写着挂在别的根下),但 b_parent_id 正确指向本页根,
|
|
// 应当被算作根的子孙 —— 否则会和祖先回溯算出矛盾结果。
|
|
loadDataApi.mockImplementation(() =>
|
|
Promise.resolve({
|
|
data: [
|
|
...FIXTURE.map((row) => ({ ...row })),
|
|
makeModule({
|
|
b_id: 'od_moved',
|
|
b_parent_id: 'base_otherdata',
|
|
b_path: '/some_stale_path/od_moved/',
|
|
}),
|
|
],
|
|
}),
|
|
)
|
|
|
|
const wrapper = await mountOtherdata()
|
|
const ids = wrapper.vm.modules.map((item) => String(item.b_id))
|
|
|
|
expect(ids).toContain('od_moved')
|
|
})
|
|
|
|
it('根不存在时树为空,不退化成显示全部模块', async () => {
|
|
loadDataApi.mockImplementation(() =>
|
|
Promise.resolve({ data: [makeModule({ b_id: 'other_root', b_path: '/other_root/' })] }),
|
|
)
|
|
|
|
const wrapper = await mountOtherdata()
|
|
|
|
expect(wrapper.vm.modules).toEqual([])
|
|
})
|
|
})
|