flnxi-Wu/lib/__tests__/material-delete-permission.test.ts
WuYongJie 63ec6b7dfb fix: 修复排行榜按钮消失、tag排序和输入框浅色模式问题
1. 排行榜悬浮窗关闭后小按钮消失问题
   - 修复面板居中模式关闭时按钮位置错误
   - 保存并恢复按钮的居中状态

2. 首页tag按钮按素材数量排序
   - 添加按素材数量降序排序逻辑

3. 上传弹窗输入框浅色模式文字不可见
   - 添加 text-slate-900 确保浅色模式下文字可见
   - 添加 placeholder 样式确保占位符正确显示
2025-12-14 21:41:29 +08:00

180 lines
6.4 KiB
TypeScript
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.

/**
* 素材删除权限验证测试
*
* **Feature: bugfix-dec-2025**
* **Property 2: 管理员素材删除权限验证**
* **Property 3: 超级管理员删除权限**
* **Validates: Requirements 3.1, 3.2, 3.3**
*
* @jest-environment node
*/
describe('素材删除权限验证', () => {
/**
* 模拟部门层级关系检查
* @param operatorScope 操作者管理的部门
* @param targetDepartment 目标素材上传者的部门
* @returns 是否在管理范围内
*/
const isDepartmentWithinScope = (
operatorScope: string,
targetDepartment: string
): boolean => {
if (!operatorScope || !targetDepartment) return false
// 同部门或子部门
return targetDepartment === operatorScope ||
targetDepartment.startsWith(`${operatorScope}-`)
}
/**
* 权限验证逻辑
* @param userId 当前用户ID
* @param isSuperAdmin 是否为超级管理员
* @param materialOwnerId 素材所有者ID
* @param operatorScope 操作者管理的部门范围
* @param targetDepartment 素材上传者所在部门
* @returns 是否有权限删除
*/
const canDeleteMaterial = (
userId: string,
isSuperAdmin: boolean,
materialOwnerId: string,
operatorScope: string = '',
targetDepartment: string = ''
): boolean => {
// 超级管理员可以删除任意素材
if (isSuperAdmin) {
return true
}
// 自己上传的素材
if (userId === materialOwnerId) {
return true
}
// 检查是否在管理范围内
if (operatorScope && targetDepartment) {
return isDepartmentWithinScope(operatorScope, targetDepartment)
}
return false
}
/**
* Property 2: 管理员素材删除权限验证
* *For any* 管理员用户和任意素材,删除操作应在素材属于该管理员或其管理的部门成员时成功
* **Feature: bugfix-dec-2025, Property 2: 管理员素材删除权限验证**
* **Validates: Requirements 3.1, 3.2**
*/
describe('Property 2: 管理员素材删除权限验证', () => {
it('管理员可以删除自己上传的素材', () => {
const result = canDeleteMaterial('admin-1', false, 'admin-1')
expect(result).toBe(true)
})
it('管理员可以删除自己管理的部门成员上传的素材', () => {
// admin-1 管理 "设计部",user-1 属于 "设计部"
const result = canDeleteMaterial('admin-1', false, 'user-1', '设计部', '设计部')
expect(result).toBe(true)
})
it('管理员可以删除子部门成员上传的素材', () => {
// admin-1 管理 "设计部",user-1 属于 "设计部-UI组"
const result = canDeleteMaterial('admin-1', false, 'user-1', '设计部', '设计部-UI组')
expect(result).toBe(true)
})
it('管理员不能删除其他部门成员上传的素材', () => {
// admin-1 管理 "设计部",user-1 属于 "技术部"
const result = canDeleteMaterial('admin-1', false, 'user-1', '设计部', '技术部')
expect(result).toBe(false)
})
it('管理员不能删除没有部门信息的其他用户素材', () => {
const result = canDeleteMaterial('admin-1', false, 'user-1', '', '')
expect(result).toBe(false)
})
// 属性测试:部门层级关系
it('对于任意管理员,可以删除自己或管理范围内的素材', () => {
const testCases = [
// 自己的素材
{ userId: 'a', ownerId: 'a', scope: '', dept: '', expected: true },
// 同部门
{ userId: 'a', ownerId: 'b', scope: '部门A', dept: '部门A', expected: true },
// 子部门
{ userId: 'a', ownerId: 'b', scope: '部门A', dept: '部门A-子部门1', expected: true },
// 孙部门
{ userId: 'a', ownerId: 'b', scope: '部门A', dept: '部门A-子部门1-小组', expected: true },
// 其他部门
{ userId: 'a', ownerId: 'b', scope: '部门A', dept: '部门B', expected: false },
// 无管理范围
{ userId: 'a', ownerId: 'b', scope: '', dept: '部门A', expected: false },
]
testCases.forEach(({ userId, ownerId, scope, dept, expected }) => {
const result = canDeleteMaterial(userId, false, ownerId, scope, dept)
expect(result).toBe(expected)
})
})
})
/**
* Property 3: 超级管理员删除权限
* *For any* 超级管理员用户和任意素材,删除操作应始终成功
* **Feature: bugfix-dec-2025, Property 3: 超级管理员删除权限**
* **Validates: Requirements 3.3**
*/
describe('Property 3: 超级管理员删除权限', () => {
it('超级管理员可以删除自己上传的素材', () => {
const result = canDeleteMaterial('super-admin', true, 'super-admin')
expect(result).toBe(true)
})
it('超级管理员可以删除其他管理员上传的素材', () => {
const result = canDeleteMaterial('super-admin', true, 'admin-1')
expect(result).toBe(true)
})
it('超级管理员可以删除任意部门用户上传的素材', () => {
const result = canDeleteMaterial('super-admin', true, 'user-1', '', '任意部门')
expect(result).toBe(true)
})
// 属性测试:对于任意超级管理员和任意素材
it('对于任意超级管理员,可以删除任意素材', () => {
const testCases = [
{ ownerId: 'super-admin', dept: '' },
{ ownerId: 'admin-1', dept: '设计部' },
{ ownerId: 'user-1', dept: '技术部' },
{ ownerId: 'user-2', dept: '市场部-销售组' },
{ ownerId: 'any-user', dept: '' },
]
testCases.forEach(({ ownerId, dept }) => {
const result = canDeleteMaterial('super-admin', true, ownerId, '', dept)
expect(result).toBe(true)
})
})
})
/**
* 边界情况测试
*/
describe('边界情况', () => {
it('空用户ID应该无法删除其他用户素材', () => {
const result = canDeleteMaterial('', false, 'some-owner')
expect(result).toBe(false)
})
it('用户ID和素材所有者ID都为空时应该可以删除(边界情况)', () => {
// 这是一个边界情况,空字符串相等
const result = canDeleteMaterial('', false, '')
expect(result).toBe(true)
})
it('部门名称包含连字符但不是子部门关系时不应该匹配', () => {
// "设计部-UI" 不是 "设计" 的子部门
const result = canDeleteMaterial('admin', false, 'user', '设计', '设计部-UI')
expect(result).toBe(false)
})
})
})