20260921173344
This commit is contained in:
1 parent
b3364fe6dc
commit
ac710c1801
5 files changed
+1000
-407
No files matched your search
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* 分配权限抽屉(UserPowerDrawer):头部结构。
|
||||
*
|
||||
* 数据加载与保存由本组件负责(面板只读展示),测试只锁头部两件事:
|
||||
* 1. 头部不渲染标题:只有页签一行 + ui/Drawer 的关闭按钮,没有其它元素;
|
||||
* 数据加载与保存由本组件负责(面板只读展示),测试只锁结构两件事:
|
||||
* 1. 头部常规显示:左侧账号标识标题 + 右侧关闭按钮,页签在内容区顶部;
|
||||
* 2. 三个页签对应三张权限表的内容面板(切换页签不销毁,用 v-show 承载)。
|
||||
*
|
||||
* 面板自身的规则由 user-power-panel.spec.js 覆盖(含「全授权 / 全禁用」),这里不重复。
|
||||
@@ -38,16 +38,28 @@ async function mountDrawer() {
|
||||
}
|
||||
|
||||
describe('分配权限抽屉:头部', () => {
|
||||
it('头部只有页签一行:无标题、无批量按钮,关闭按钮由 ui/Drawer 提供', async () => {
|
||||
it('头部常规显示:账号标识标题 + 关闭按钮,页签在内容区', async () => {
|
||||
const wrapper = await mountDrawer()
|
||||
|
||||
expect(wrapper.find('.fms-drawer-title').exists()).toBe(false)
|
||||
expect(wrapper.find('.fms-drawer-extra .tabs-nav').exists()).toBe(true)
|
||||
expect(wrapper.find('.fms-drawer-title').text()).toBe('分配权限 · 张三(001)')
|
||||
expect(wrapper.find('.fms-drawer-close').exists()).toBe(true)
|
||||
// header 让给账号标识:页签不在 header 里,在内容区顶部
|
||||
expect(wrapper.find('.fms-drawer-header .tabs-nav').exists()).toBe(false)
|
||||
expect(wrapper.find('.power-drawer__nav .tabs-nav').exists()).toBe(true)
|
||||
// 账号级批量按钮不在头部(在功能权限面板的工具栏里)
|
||||
expect(wrapper.find('.fms-drawer-header button.button').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('账号缺名称时标题只回退到编码', async () => {
|
||||
const wrapper = mount(UserPowerDrawer, {
|
||||
props: { open: true, user: { b_id: '001' } },
|
||||
global: { stubs: { teleport: true } },
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.fms-drawer-title').text()).toBe('分配权限 · 001')
|
||||
})
|
||||
|
||||
it('三个页签对应三张权限表的内容面板', async () => {
|
||||
const wrapper = await mountDrawer()
|
||||
|
||||
|
||||
@@ -4,14 +4,16 @@
|
||||
* 数据加载与保存由父级 UserPowerDrawer 负责,面板自身只做这几件事,测试只锁这几件:
|
||||
* 1. 打开时的初始状态:只展开「全部分类」虚拟根,业务目录收起、不选中任何菜单;
|
||||
* 2. 菜单选中语义:重复点击已选中的菜单不取消选中,只有点「全部分类」才清空;
|
||||
* 3. 右侧两个分区:菜单访问(入口开关)+ 模块权限
|
||||
* (模块名 | 模块使用开关 | 操作权限 chip | 行尾全选与计数)。
|
||||
* 目录不渲染入口开关、没配权限点的模块不渲染,都不出空态文案;
|
||||
* 3. 右侧结构:页头(菜单名 + 入口勾选框 + 本页进度)+ 一张「模块 / 动作 / 已选」三列表。
|
||||
* 模块级勾选在「模块」列、动作勾选在「动作」列,层级靠列而不是靠嵌套容器;
|
||||
* 目录不渲染入口勾选框、没配权限点的模块不渲染,都不出空态文案;
|
||||
* 4. 面板顶部工具栏的「全授权 / 全禁用」作用于该账号的全部功能权限(s_power 全量),
|
||||
* 与左侧选中哪个菜单无关;
|
||||
* 5. 勾选结果经 v-model 回传,三层是「保护性单向联动」:
|
||||
* 勾动作补模块使用与入口,勾模块补入口,关模块清该模块动作,
|
||||
* 关入口收回该菜单下的全部授权。
|
||||
* 勾动作补模块使用与入口,模块级勾选框全给全撤,关入口收回该菜单下的全部授权。
|
||||
*
|
||||
* 勾选框是 ui/Checkbox(label 包原生 input),测试直接驱动 input 的 change ——
|
||||
* jsdom 不保证 label 点击会转发给内部控件,走 change 才是组件真实监听的入口。
|
||||
*/
|
||||
import { describe, it, expect, beforeEach } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
@@ -30,7 +32,11 @@ const MENU_TREE = [
|
||||
]
|
||||
|
||||
const MENU_MODULES = {
|
||||
partner: [{ b_menu_id: 'partner', b_module_id: 'v_b_othercompany', b_xh: 10 }],
|
||||
// 合作伙伴菜单绑两个模块,动作集不同 → 验证动作各自成组、互不影响
|
||||
partner: [
|
||||
{ b_menu_id: 'partner', b_module_id: 'v_b_othercompany', b_xh: 10 },
|
||||
{ b_menu_id: 'partner', b_module_id: 'v_b_contact', b_xh: 20 },
|
||||
],
|
||||
// 用户管理绑两个模块,其中币种(b_money)没配权限点 → 验证「未配置权限点的模块不渲染」
|
||||
user: [
|
||||
{ b_menu_id: 'user', b_module_id: 'v_b_user', b_xh: 10 },
|
||||
@@ -40,14 +46,24 @@ const MENU_MODULES = {
|
||||
|
||||
const MODULE_BY_ID = new Map([
|
||||
['v_b_othercompany', { b_id: 'v_b_othercompany', b_name: '合作伙伴' }],
|
||||
['v_b_contact', { b_id: 'v_b_contact', b_name: '联系人' }],
|
||||
['v_b_user', { b_id: 'v_b_user', b_name: '用户管理' }],
|
||||
['b_money', { b_id: 'b_money', b_name: '币种' }],
|
||||
])
|
||||
|
||||
/** 每个模块的权限点:access 是「模块使用」(并入模块级勾选框),其余是「动作」列 */
|
||||
const POWER_BY_MODULE = {
|
||||
v_b_othercompany: [
|
||||
{ b_id: 'module.v_b_othercompany', b_name: '模块使用', b_action: 'access' },
|
||||
{ b_id: 'action.v_b_othercompany.create', b_name: '新增', b_action: 'create' },
|
||||
{ b_id: 'action.v_b_othercompany.update', b_name: '修改', b_action: 'update' },
|
||||
{ b_id: 'action.v_b_othercompany.audit', b_name: '审核', b_action: 'audit' },
|
||||
],
|
||||
// 联系人只有新增 / 删除:动作列也只剩这两项
|
||||
v_b_contact: [
|
||||
{ b_id: 'module.v_b_contact', b_name: '模块使用', b_action: 'access' },
|
||||
{ b_id: 'action.v_b_contact.create', b_name: '新增', b_action: 'create' },
|
||||
{ b_id: 'action.v_b_contact.delete', b_name: '删除', b_action: 'delete' },
|
||||
],
|
||||
v_b_user: [{ b_id: 'module.v_b_user', b_name: '模块使用', b_action: 'access' }],
|
||||
}
|
||||
@@ -59,9 +75,22 @@ const ALL_POWER_IDS = [
|
||||
'menu.user',
|
||||
'module.v_b_othercompany',
|
||||
'action.v_b_othercompany.create',
|
||||
'action.v_b_othercompany.update',
|
||||
'action.v_b_othercompany.audit',
|
||||
'module.v_b_contact',
|
||||
'action.v_b_contact.create',
|
||||
'action.v_b_contact.delete',
|
||||
'module.v_b_user',
|
||||
]
|
||||
|
||||
/** 合作伙伴模块(v_b_othercompany)的权限点全量:模块级勾选框勾上时就该是这些 */
|
||||
const OTHERCOMPANY_ALL = [
|
||||
'module.v_b_othercompany',
|
||||
'action.v_b_othercompany.create',
|
||||
'action.v_b_othercompany.update',
|
||||
'action.v_b_othercompany.audit',
|
||||
]
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear()
|
||||
sessionStorage.clear()
|
||||
@@ -95,26 +124,59 @@ function findRow(wrapper, text) {
|
||||
return wrapper.findAll('.tree-node').find((row) => row.text().includes(text))
|
||||
}
|
||||
|
||||
/** 分区标题清单 */
|
||||
function sectionTitles(wrapper) {
|
||||
return wrapper.findAll('.power-section__title').map((el) => el.text())
|
||||
}
|
||||
|
||||
/** 模块权限区的行名清单(跳过「菜单访问」分区的那一行) */
|
||||
/** 模块行的模块名清单(按行顺序) */
|
||||
function moduleNames(wrapper) {
|
||||
const section = wrapper.findAll('.power-section')[1]
|
||||
return section ? section.findAll('.power-row__name').map((el) => el.text()) : []
|
||||
return wrapper.findAll('.power-row__module .checkbox-label').map((el) => el.text())
|
||||
}
|
||||
|
||||
/** 「菜单访问」分区的入口开关(目录没有入口权限点时返回 undefined) */
|
||||
function entrySwitch(wrapper) {
|
||||
return wrapper.findAll('.power-section')[0]?.find('[role="switch"]')
|
||||
/** 页头(菜单名 + 入口)的入口勾选框(目录没有入口权限点时返回 undefined) */
|
||||
function entryCheck(wrapper) {
|
||||
const found = wrapper.find('.power-head__entry')
|
||||
return found.exists() ? found : undefined
|
||||
}
|
||||
|
||||
/** 模块权限区的模块使用开关(第 index 行) */
|
||||
function moduleSwitch(wrapper, index = 0) {
|
||||
const section = wrapper.findAll('.power-section')[1]
|
||||
return section ? section.findAll('[role="switch"]')[index] : undefined
|
||||
/** 第 index 个模块行的模块级勾选框 */
|
||||
function moduleCheck(wrapper, index = 0) {
|
||||
return wrapper.findAll('.power-row__module .checkbox')[index]
|
||||
}
|
||||
|
||||
/** 勾选框形态的开关总数:页头入口 1 个 + 每行模块 1 个(动作勾选框在「动作」列,不计入) */
|
||||
function useChecks(wrapper) {
|
||||
return wrapper.findAll('.power-head__entry, .power-row__module .checkbox')
|
||||
}
|
||||
|
||||
/** 第 index 行行尾的「已选」计数 */
|
||||
function rowCount(wrapper, index = 0) {
|
||||
return wrapper.findAll('.power-row .power-col--count')[index]
|
||||
}
|
||||
|
||||
/** 某个模块行(按模块名定位,比按下标稳) */
|
||||
function moduleRow(wrapper, moduleName) {
|
||||
return wrapper
|
||||
.findAll('.power-row')
|
||||
.find((row) => row.find('.power-row__module .checkbox-label').text() === moduleName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 动作勾选框:按「模块名 + 动作名」定位。
|
||||
* 动作只有「动作」列有,所以按名字找比按下标找稳,动作数量变化也不影响。
|
||||
*/
|
||||
function actionCheck(wrapper, moduleName, actionName) {
|
||||
return moduleRow(wrapper, moduleName)
|
||||
.findAll('.power-row__actions .checkbox')
|
||||
.find((el) => el.find('.checkbox-label').text() === actionName)
|
||||
}
|
||||
|
||||
/** 某个模块的动作名清单(按铺排顺序) */
|
||||
function actionNames(wrapper, moduleName) {
|
||||
return moduleRow(wrapper, moduleName)
|
||||
.findAll('.power-row__actions .checkbox-label')
|
||||
.map((el) => el.text())
|
||||
}
|
||||
|
||||
/** 驱动 ui/Checkbox 内部的原生 input:勾上 / 取消 */
|
||||
function setCheck(checkbox, checked = true) {
|
||||
return checkbox.find('.checkbox-input').setValue(checked)
|
||||
}
|
||||
|
||||
/** 面板顶部工具栏按钮:0 = 全授权,1 = 全禁用 */
|
||||
@@ -199,54 +261,137 @@ describe('功能权限面板:菜单选中语义', () => {
|
||||
})
|
||||
|
||||
describe('功能权限面板:右侧结构', () => {
|
||||
it('两个分区:菜单访问 + 模块权限;入口与模块使用各一个开关', async () => {
|
||||
it('页头:菜单名做标题 + 入口勾选框 + 本页进度', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
expect(sectionTitles(wrapper)).toEqual(['菜单访问', '模块权限'])
|
||||
expect(wrapper.findAll('.power-section')[0].find('.power-row__name').text()).toBe('合作伙伴')
|
||||
expect(moduleNames(wrapper)).toEqual(['合作伙伴'])
|
||||
// 开关只有两处:菜单访问 + 模块使用
|
||||
expect(wrapper.findAll('[role="switch"]')).toHaveLength(2)
|
||||
// chip 只剩业务动作,模块使用不再混在里面
|
||||
expect(wrapper.findAll('.power-chip').map((el) => el.text())).toEqual(['新增'])
|
||||
expect(wrapper.find('.power-head__name').text()).toBe('合作伙伴')
|
||||
expect(entryCheck(wrapper).find('.checkbox-label').text()).toBe('可访问')
|
||||
expect(wrapper.find('.power-head__meta').text()).toBe('本页 2 个模块,已授权 0 个')
|
||||
// 页头里只有菜单名、勾选框与进度,没有多余的说明句
|
||||
expect(wrapper.find('.power-head').text()).toBe('合作伙伴 可访问 本页 2 个模块,已授权 0 个')
|
||||
})
|
||||
|
||||
it('本页进度:至少给了一项权限的模块才计入已授权', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['menu.partner', 'module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
expect(wrapper.find('.power-head__meta').text()).toBe('本页 2 个模块,已授权 1 个')
|
||||
})
|
||||
|
||||
it('入口的连带影响只进 title,不常显在页头', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
expect(entryCheck(wrapper).attributes('title')).toBe(
|
||||
'可访问「合作伙伴」(关闭会收回该页面下的全部模块授权)',
|
||||
)
|
||||
})
|
||||
|
||||
it('表格:模块 / 动作 / 已选三列,一个模块一行', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
expect(wrapper.find('.power-grid__head').text()).toBe('模块动作已选')
|
||||
expect(moduleNames(wrapper)).toEqual(['合作伙伴', '联系人'])
|
||||
expect(wrapper.findAll('.power-row')).toHaveLength(2)
|
||||
// 勾选框形态的开关:页头入口 1 个 + 模块级 2 个(动作勾选框在「动作」列,不计入)
|
||||
expect(useChecks(wrapper)).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('动作按模块分行:每行的动作只属于该行模块,互不挤占', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
expect(actionNames(wrapper, '合作伙伴')).toEqual(['新增', '修改', '审核'])
|
||||
expect(actionNames(wrapper, '联系人')).toEqual(['新增', '删除'])
|
||||
})
|
||||
|
||||
it('动作勾选框挂 title(模块名 + 动作名),名称超长被省略时可查看全称', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
expect(actionCheck(wrapper, '合作伙伴', '新增').attributes('title')).toBe('合作伙伴 新增')
|
||||
})
|
||||
|
||||
it('行尾「已选 x/y」= 该模块已授权的动作数 / 动作总数', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
// 「模块使用」不计入已选:它并入模块级勾选框,与「动作」列不是一回事
|
||||
expect(rowCount(wrapper, 0).text()).toBe('1/3')
|
||||
expect(rowCount(wrapper, 1).text()).toBe('0/2')
|
||||
})
|
||||
|
||||
it('只有模块使用、没有动作的模块不显示计数', async () => {
|
||||
const wrapper = await mountWithMenu('user')
|
||||
|
||||
expect(moduleNames(wrapper)).toEqual(['用户管理'])
|
||||
expect(rowCount(wrapper, 0).text()).toBe('')
|
||||
})
|
||||
|
||||
it('模块级勾选框三态:全选 / 半选 / 未选', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
// 全选:模块使用 + 全部动作都在
|
||||
await wrapper.setProps({ modelValue: OTHERCOMPANY_ALL })
|
||||
expect(moduleCheck(wrapper, 0).classes()).toContain('checkbox-checked')
|
||||
expect(moduleCheck(wrapper, 0).classes()).not.toContain('checkbox-indeterminate')
|
||||
|
||||
// 半选:进了这个模块,但只给了部分动作
|
||||
await wrapper.setProps({
|
||||
modelValue: ['module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
expect(moduleCheck(wrapper, 0).classes()).not.toContain('checkbox-checked')
|
||||
expect(moduleCheck(wrapper, 0).classes()).toContain('checkbox-indeterminate')
|
||||
|
||||
// 未选
|
||||
await wrapper.setProps({ modelValue: [] })
|
||||
expect(moduleCheck(wrapper, 0).classes()).not.toContain('checkbox-checked')
|
||||
expect(moduleCheck(wrapper, 0).classes()).not.toContain('checkbox-indeterminate')
|
||||
})
|
||||
|
||||
it('模块级勾选框的 title 说清点它会全给还是全撤', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
expect(moduleCheck(wrapper, 0).attributes('title')).toBe('全选「合作伙伴」的 4 项权限')
|
||||
|
||||
await wrapper.setProps({ modelValue: OTHERCOMPANY_ALL })
|
||||
expect(moduleCheck(wrapper, 0).attributes('title')).toBe('取消「合作伙伴」的全部授权')
|
||||
})
|
||||
|
||||
it('已授权的入口渲染为打开态', async () => {
|
||||
const wrapper = await mountWithMenu('partner', { modelValue: ['menu.partner'] })
|
||||
|
||||
expect(wrapper.vm.menuPowerCode).toBe('menu.partner')
|
||||
expect(entrySwitch(wrapper).attributes('aria-checked')).toBe('true')
|
||||
expect(entryCheck(wrapper).classes()).toContain('checkbox-checked')
|
||||
})
|
||||
|
||||
it('目录:不渲染入口开关(没有 menu.* 权限点),只给一行说明', async () => {
|
||||
it('目录:不渲染入口勾选框(没有 menu.* 权限点),只在页头说明原因', async () => {
|
||||
const wrapper = await mountWithMenu('base')
|
||||
|
||||
expect(sectionTitles(wrapper)).toEqual(['菜单访问'])
|
||||
expect(wrapper.findAll('[role="switch"]')).toHaveLength(0)
|
||||
expect(wrapper.find('.power-panel__hint').text()).toContain('目录只是分组节点')
|
||||
expect(useChecks(wrapper)).toHaveLength(0)
|
||||
// 目录没有可勾的入口:页头只显示名称,不出现勾选框
|
||||
expect(entryCheck(wrapper)).toBeUndefined()
|
||||
expect(wrapper.find('.power-head__name').text()).toBe('基础资料')
|
||||
expect(wrapper.find('.power-head__note').text()).toBe('目录不需要单独授权')
|
||||
})
|
||||
|
||||
it('外链菜单:没有可授权模块,入口开关独立可用', async () => {
|
||||
it('外链菜单:没有可授权模块,连表头都不渲染,入口勾选框独立可用', async () => {
|
||||
const wrapper = await mountWithMenu('portal')
|
||||
|
||||
expect(sectionTitles(wrapper)).toEqual(['菜单访问'])
|
||||
expect(moduleNames(wrapper)).toEqual([])
|
||||
expect(wrapper.findAll('.power-row')).toHaveLength(0)
|
||||
expect(wrapper.find('.power-grid').exists()).toBe(false)
|
||||
expect(wrapper.find('.power-head__meta').exists()).toBe(false)
|
||||
|
||||
await entrySwitch(wrapper).trigger('click')
|
||||
await nextTick()
|
||||
|
||||
await setCheck(entryCheck(wrapper))
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.portal'])
|
||||
})
|
||||
|
||||
it('页面没绑模块(自定义页):只剩入口开关,勾选即全部权限', async () => {
|
||||
it('页面没绑模块(自定义页):只剩入口勾选框,勾选即全部权限', async () => {
|
||||
const wrapper = await mountWithMenu('partner', { menuModules: {} })
|
||||
|
||||
expect(sectionTitles(wrapper)).toEqual(['菜单访问'])
|
||||
expect(wrapper.findAll('[role="switch"]')).toHaveLength(1)
|
||||
|
||||
await entrySwitch(wrapper).trigger('click')
|
||||
await nextTick()
|
||||
expect(wrapper.find('.power-grid').exists()).toBe(false)
|
||||
expect(useChecks(wrapper)).toHaveLength(1)
|
||||
|
||||
await setCheck(entryCheck(wrapper))
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.partner'])
|
||||
})
|
||||
|
||||
@@ -255,6 +400,8 @@ describe('功能权限面板:右侧结构', () => {
|
||||
|
||||
// 「币种」绑定了但没配权限点:不渲染成行,也不出任何提示
|
||||
expect(moduleNames(wrapper)).toEqual(['用户管理'])
|
||||
// 只有模块使用权限点的模块没有动作勾选框
|
||||
expect(wrapper.findAll('.power-row__actions .checkbox')).toHaveLength(0)
|
||||
expect(wrapper.find('.power-panel__main').text()).not.toContain('未配置权限点')
|
||||
})
|
||||
})
|
||||
@@ -299,19 +446,41 @@ describe('功能权限面板:全授权 / 全禁用', () => {
|
||||
})
|
||||
|
||||
describe('功能权限面板:三层联动', () => {
|
||||
it('勾模块使用:自动补上菜单入口', async () => {
|
||||
it('勾模块级勾选框:一次给全该模块的权限点,并补上菜单入口', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
await moduleSwitch(wrapper).trigger('click')
|
||||
await setCheck(moduleCheck(wrapper))
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual(['module.v_b_othercompany', 'menu.partner'])
|
||||
expect(lastEmitted(wrapper)).toEqual([...OTHERCOMPANY_ALL, 'menu.partner'])
|
||||
})
|
||||
|
||||
it('勾操作权限:自动补上模块使用与菜单入口', async () => {
|
||||
it('半选时点模块级勾选框:补齐到全选,不产生重复项', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
await setCheck(moduleCheck(wrapper))
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual([...OTHERCOMPANY_ALL, 'menu.partner'])
|
||||
})
|
||||
|
||||
it('取消模块级勾选框:收回该模块的全部权限点,不动菜单入口', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['menu.partner', ...OTHERCOMPANY_ALL],
|
||||
})
|
||||
|
||||
await setCheck(moduleCheck(wrapper), false)
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.partner'])
|
||||
})
|
||||
|
||||
it('勾单个动作:自动补上模块使用与菜单入口', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
await wrapper.findAll('.power-chip')[0].trigger('click')
|
||||
await setCheck(actionCheck(wrapper, '合作伙伴', '新增'))
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual([
|
||||
@@ -321,21 +490,23 @@ describe('功能权限面板:三层联动', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('关模块使用:只清该模块的操作权限,不动菜单入口', async () => {
|
||||
it('取消单个动作:不动模块使用与入口,模块级勾选框落到半选', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['menu.partner', 'module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
await moduleSwitch(wrapper).trigger('click')
|
||||
await setCheck(actionCheck(wrapper, '合作伙伴', '新增'), false)
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.partner'])
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.partner', 'module.v_b_othercompany'])
|
||||
expect(moduleCheck(wrapper, 0).classes()).toContain('checkbox-indeterminate')
|
||||
expect(rowCount(wrapper, 0).text()).toBe('0/3')
|
||||
})
|
||||
|
||||
it('开菜单入口:只补入口本身,不给任何模块权限', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
await entrySwitch(wrapper).trigger('click')
|
||||
await setCheck(entryCheck(wrapper))
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.partner'])
|
||||
@@ -346,44 +517,22 @@ describe('功能权限面板:三层联动', () => {
|
||||
modelValue: ['menu.partner', 'module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
await entrySwitch(wrapper).trigger('click')
|
||||
await setCheck(entryCheck(wrapper), false)
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual([])
|
||||
})
|
||||
|
||||
it('取消单个操作权限:不动模块使用与入口', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['menu.partner', 'module.v_b_othercompany', 'action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
await wrapper.findAll('.power-chip')[0].trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual(['menu.partner', 'module.v_b_othercompany'])
|
||||
})
|
||||
|
||||
it('勾选态回显:操作权限 chip 与模块使用开关各管各的', async () => {
|
||||
it('勾选态回显:各行动作各管各的,只勾动作时模块级是半选', async () => {
|
||||
const wrapper = await mountWithMenu('partner', {
|
||||
modelValue: ['action.v_b_othercompany.create'],
|
||||
})
|
||||
|
||||
expect(wrapper.findAll('.power-chip')[0].classes()).toContain('is-checked')
|
||||
expect(wrapper.findAll('.power-chip')[0].attributes('aria-checked')).toBe('true')
|
||||
// 模块使用未授权 → 开关是关的
|
||||
expect(moduleSwitch(wrapper).attributes('aria-checked')).toBe('false')
|
||||
})
|
||||
|
||||
it('行尾「全选」:补齐该模块的权限点并联动入口', async () => {
|
||||
const wrapper = await mountWithMenu('partner')
|
||||
|
||||
await wrapper.find('.power-row__toggle').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(lastEmitted(wrapper)).toEqual([
|
||||
'module.v_b_othercompany',
|
||||
'action.v_b_othercompany.create',
|
||||
'menu.partner',
|
||||
])
|
||||
expect(actionCheck(wrapper, '合作伙伴', '新增').classes()).toContain('checkbox-checked')
|
||||
expect(actionCheck(wrapper, '合作伙伴', '修改').classes()).not.toContain('checkbox-checked')
|
||||
// 同名动作在别的模块行里不受影响
|
||||
expect(actionCheck(wrapper, '联系人', '新增').classes()).not.toContain('checkbox-checked')
|
||||
// 只勾了动作、没勾模块使用 → 模块级勾选框半选
|
||||
expect(moduleCheck(wrapper, 0).classes()).toContain('checkbox-indeterminate')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user