212 lines
8.3 KiB
TypeScript
212 lines
8.3 KiB
TypeScript
import { createPinia, setActivePinia } from 'pinia'
|
|
import { flushPromises, shallowMount } from '@vue/test-utils'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { listPlatformPermissions, type PlatformPermissionResource } from '@/modules/iam/api/platformIam'
|
|
import { useAuthStore } from '@/core/auth/auth'
|
|
import PermissionsView from './PermissionsView.vue'
|
|
|
|
vi.mock('@/modules/iam/api/platformIam', () => ({
|
|
changePlatformPermissionStatus: vi.fn(),
|
|
createPlatformPermission: vi.fn(),
|
|
deletePlatformPermission: vi.fn(),
|
|
listPlatformPermissions: vi.fn(),
|
|
updatePlatformPermission: vi.fn(),
|
|
}))
|
|
|
|
const permission: PlatformPermissionResource = {
|
|
id: 5100010,
|
|
tenantId: 0,
|
|
appCode: 'PLATFORM',
|
|
permissionType: 'MENU',
|
|
parentId: 0,
|
|
permissionCode: 'platform:customer:list',
|
|
permissionName: '企业客户',
|
|
routePath: '/customers',
|
|
httpMethod: null,
|
|
sortNo: 10,
|
|
status: 'ACTIVE',
|
|
}
|
|
|
|
const allActionPermissions = [
|
|
'platform:permission:list',
|
|
'platform:permission:create',
|
|
'platform:permission:edit',
|
|
'platform:permission:status',
|
|
'platform:permission:delete',
|
|
]
|
|
|
|
function mountServerView(permissionCodes = ['platform:permission:list', 'platform:permission:create']) {
|
|
const pinia = createPinia()
|
|
setActivePinia(pinia)
|
|
const auth = useAuthStore()
|
|
auth.isServerSession = true
|
|
auth.permissions = permissionCodes
|
|
return shallowMount(PermissionsView, {
|
|
global: {
|
|
plugins: [pinia],
|
|
directives: { loading: () => undefined },
|
|
stubs: {
|
|
AdminPage: { template: '<main><slot /></main>' },
|
|
ListPageLayout: { template: '<section><slot name="toolbar" /><slot name="state" /><slot /></section>' },
|
|
FormSection: { template: '<section><slot /></section>' },
|
|
AppDrawer: { template: '<section><slot /><slot name="footer" /></section>' },
|
|
LoadErrorState: { props: ['message'], template: '<div role="alert">{{ message }}<slot name="details" /></div>' },
|
|
DataTable: {
|
|
props: ['data'],
|
|
template: '<section><slot name="toolbar-actions" /><div v-for="row in data" :key="row.id" class="row-actions" :data-row-id="row.id"><slot name="actions" :row="row" /></div><span data-testid="row-count">{{ data.length }}</span></section>',
|
|
},
|
|
'el-alert': { props: ['title'], template: '<div role="alert">{{ title }}<slot name="title" /></div>' },
|
|
'el-input': true,
|
|
'el-option': true,
|
|
'el-select': true,
|
|
'el-button': { props: ['disabled'], template: '<button :disabled="disabled"><slot /></button>' },
|
|
'el-dropdown': { template: '<div class="dropdown"><slot /><slot name="dropdown" /></div>' },
|
|
'el-dropdown-menu': { template: '<div><slot /></div>' },
|
|
'el-dropdown-item': { props: ['disabled'], template: '<button class="dropdown-item" :disabled="disabled"><slot /></button>' },
|
|
'el-table': true,
|
|
'el-table-column': true,
|
|
'el-input-number': true,
|
|
'el-radio-group': true,
|
|
'el-radio-button': true,
|
|
'el-drawer': { template: '<section><slot /><slot name="footer" /></section>' },
|
|
'el-form': { template: '<form><slot /></form>' },
|
|
'el-form-item': { template: '<label><slot /></label>' },
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
describe('PermissionsView IAM mode', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(listPlatformPermissions).mockReset()
|
|
})
|
|
|
|
it('loads the platform permission resource tree from IAM', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([permission])
|
|
|
|
const wrapper = mountServerView()
|
|
await flushPromises()
|
|
|
|
expect(listPlatformPermissions).toHaveBeenCalledTimes(1)
|
|
expect(wrapper.text()).not.toContain('权限资源树')
|
|
})
|
|
|
|
it('shows a recoverable state when the permission list fails', async () => {
|
|
vi.mocked(listPlatformPermissions).mockRejectedValue(new Error('IAM unavailable'))
|
|
|
|
const wrapper = mountServerView()
|
|
await flushPromises()
|
|
|
|
const alertText = wrapper.findAll('[role="alert"]').map((item) => item.text()).join(' ')
|
|
expect(alertText).toContain('权限资源加载失败,请稍后重试')
|
|
expect(alertText).not.toContain('IAM unavailable')
|
|
})
|
|
|
|
it('shows only add-child directly for a built-in menu even with all permissions', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([{ ...permission, builtIn: true }])
|
|
|
|
const wrapper = mountServerView(allActionPermissions)
|
|
await flushPromises()
|
|
|
|
const actions = wrapper.get('[data-row-id="5100010"]')
|
|
expect(actions.text()).toContain('添加下级')
|
|
expect(actions.text()).not.toContain('系统内置')
|
|
expect(actions.text()).not.toContain('编辑')
|
|
expect(actions.text()).not.toContain('停用')
|
|
expect(actions.text()).not.toContain('删除')
|
|
expect(actions.find('.dropdown').exists()).toBe(false)
|
|
})
|
|
|
|
it('keeps three frequent actions direct and moves delete into more for a custom menu', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([{ ...permission, builtIn: false }])
|
|
|
|
const wrapper = mountServerView(allActionPermissions)
|
|
await flushPromises()
|
|
|
|
const actions = wrapper.get('[data-row-id="5100010"]')
|
|
expect(actions.text()).toContain('添加下级')
|
|
expect(actions.text()).toContain('编辑')
|
|
expect(actions.text()).toContain('停用')
|
|
expect(actions.get('.dropdown').text()).toContain('删除')
|
|
expect(actions.get('.dropdown-item').classes()).toContain('danger-menu-item')
|
|
expect(actions.get('[aria-label="企业客户的更多操作"]').attributes('title')).toBe('企业客户的更多操作')
|
|
})
|
|
|
|
it('shows edit, status, and delete directly for a custom non-menu resource', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([{
|
|
...permission,
|
|
permissionType: 'BUTTON',
|
|
permissionCode: 'platform:customer:edit',
|
|
permissionName: '编辑企业客户',
|
|
routePath: null,
|
|
builtIn: false,
|
|
}])
|
|
|
|
const wrapper = mountServerView(allActionPermissions)
|
|
await flushPromises()
|
|
|
|
const actions = wrapper.get('[data-row-id="5100010"]')
|
|
expect(actions.text()).not.toContain('添加下级')
|
|
expect(actions.text()).toContain('编辑')
|
|
expect(actions.text()).toContain('停用')
|
|
expect(actions.text()).toContain('删除')
|
|
expect(actions.find('.dropdown').exists()).toBe(false)
|
|
})
|
|
|
|
it('shows all three actually available menu actions directly when permissions are reduced', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([{ ...permission, builtIn: false }])
|
|
|
|
const wrapper = mountServerView([
|
|
'platform:permission:list',
|
|
'platform:permission:create',
|
|
'platform:permission:edit',
|
|
'platform:permission:delete',
|
|
])
|
|
await flushPromises()
|
|
|
|
const actions = wrapper.get('[data-row-id="5100010"]')
|
|
expect(actions.text()).toContain('添加下级')
|
|
expect(actions.text()).toContain('编辑')
|
|
expect(actions.text()).toContain('删除')
|
|
expect(actions.text()).not.toContain('停用')
|
|
expect(actions.find('.dropdown').exists()).toBe(false)
|
|
})
|
|
|
|
it('falls back from a missing name and code to the row id for the more-action label', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([{
|
|
...permission,
|
|
permissionName: '',
|
|
permissionCode: '',
|
|
builtIn: false,
|
|
}])
|
|
|
|
const wrapper = mountServerView(allActionPermissions)
|
|
await flushPromises()
|
|
|
|
const moreButton = wrapper.get('[data-row-id="5100010"] [aria-label="当前权限的更多操作"]')
|
|
expect(moreButton.attributes('title')).toBe('当前权限的更多操作')
|
|
expect(moreButton.attributes('aria-label')).not.toMatch(/undefined|null/)
|
|
})
|
|
|
|
it('gives more-action buttons distinct accessible names across rows', async () => {
|
|
vi.mocked(listPlatformPermissions).mockResolvedValue([
|
|
{ ...permission, builtIn: false },
|
|
{
|
|
...permission,
|
|
id: 5100020,
|
|
permissionCode: 'platform:role:list',
|
|
permissionName: '角色管理',
|
|
routePath: '/roles',
|
|
builtIn: false,
|
|
},
|
|
])
|
|
|
|
const wrapper = mountServerView(allActionPermissions)
|
|
await flushPromises()
|
|
|
|
const labels = wrapper.findAll('[aria-label$="的更多操作"]').map((button) => button.attributes('aria-label'))
|
|
expect(labels).toEqual(['企业客户的更多操作', '角色管理的更多操作'])
|
|
expect(new Set(labels).size).toBe(labels.length)
|
|
})
|
|
})
|