178 lines
5.3 KiB
TypeScript
178 lines
5.3 KiB
TypeScript
import { NextRequest } from 'next/server'
|
|
|
|
jest.mock('@/lib/auth', () => ({
|
|
authOptions: {},
|
|
}))
|
|
|
|
jest.mock('next-auth', () => ({
|
|
getServerSession: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/prisma', () => ({
|
|
prisma: {
|
|
department: {
|
|
findUnique: jest.fn(),
|
|
findMany: jest.fn(),
|
|
create: jest.fn(),
|
|
deleteMany: jest.fn(),
|
|
},
|
|
user: {
|
|
findUnique: jest.fn(),
|
|
findMany: jest.fn(),
|
|
updateMany: jest.fn(),
|
|
update: jest.fn(),
|
|
},
|
|
$transaction: jest.fn(),
|
|
},
|
|
}))
|
|
|
|
jest.mock('@/lib/license', () => ({
|
|
canUseDepartmentIsolation: jest.fn(),
|
|
planDepartmentStructureChangeWithPaidCore: jest.fn(),
|
|
}))
|
|
|
|
const { getServerSession } = require('next-auth')
|
|
const { prisma } = require('@/lib/prisma')
|
|
const { canUseDepartmentIsolation, planDepartmentStructureChangeWithPaidCore } = require('@/lib/license')
|
|
|
|
import { POST, PATCH, DELETE } from '../route'
|
|
|
|
describe('departments route license guard', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
getServerSession.mockResolvedValue({
|
|
user: { id: 'admin-id', role: 'ADMIN' },
|
|
})
|
|
prisma.user.findUnique.mockResolvedValue({ isSuperAdmin: true })
|
|
prisma.department.findMany.mockResolvedValue([])
|
|
planDepartmentStructureChangeWithPaidCore.mockImplementation(async ({ action, target }: any) => {
|
|
if (action === 'create') {
|
|
return {
|
|
valid: true,
|
|
allowed: true,
|
|
action,
|
|
departmentOps: [{ type: 'create', data: { name: String(target.name).trim() } }],
|
|
userOps: [],
|
|
}
|
|
}
|
|
|
|
return {
|
|
valid: false,
|
|
allowed: false,
|
|
error: '未设置测试计划',
|
|
errorCode: 'TEST_PLAN_MISSING',
|
|
statusCode: 500,
|
|
}
|
|
})
|
|
canUseDepartmentIsolation.mockResolvedValue(true)
|
|
})
|
|
|
|
test('POST 普通管理员不能创建部门', async () => {
|
|
prisma.user.findUnique.mockResolvedValue({ isSuperAdmin: false })
|
|
|
|
const request = new NextRequest('http://localhost/api/departments', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ name: '设计部' }),
|
|
})
|
|
|
|
const response = await POST(request)
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('最高权限')
|
|
expect(canUseDepartmentIsolation).not.toHaveBeenCalled()
|
|
expect(prisma.department.create).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('POST 最高权限账号可以创建部门', async () => {
|
|
prisma.department.create.mockResolvedValue({ id: 'dept-1', name: '设计部' })
|
|
|
|
const request = new NextRequest('http://localhost/api/departments', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ name: '设计部' }),
|
|
})
|
|
|
|
const response = await POST(request)
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(201)
|
|
expect(data.name).toBe('设计部')
|
|
expect(planDepartmentStructureChangeWithPaidCore).toHaveBeenCalledWith({
|
|
action: 'create',
|
|
target: { name: '设计部' },
|
|
departments: [],
|
|
})
|
|
expect(prisma.department.create).toHaveBeenCalledWith({ data: { name: '设计部' } })
|
|
})
|
|
|
|
test('PATCH 应在许可证不支持时返回 403', async () => {
|
|
canUseDepartmentIsolation.mockResolvedValue(false)
|
|
|
|
const request = new NextRequest('http://localhost/api/departments', {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({
|
|
id: 'dept-1',
|
|
name: '新部门',
|
|
}),
|
|
})
|
|
|
|
const response = await PATCH(request)
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('当前许可证未包含部门隔离功能')
|
|
expect(prisma.department.findUnique).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('PATCH 普通管理员不能重命名部门', async () => {
|
|
prisma.user.findUnique.mockResolvedValue({ isSuperAdmin: false })
|
|
|
|
const request = new NextRequest('http://localhost/api/departments', {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({
|
|
id: 'dept-1',
|
|
name: '新部门',
|
|
}),
|
|
})
|
|
|
|
const response = await PATCH(request)
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('最高权限')
|
|
expect(canUseDepartmentIsolation).not.toHaveBeenCalled()
|
|
expect(prisma.department.findUnique).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('DELETE 应在许可证不支持时返回 403', async () => {
|
|
canUseDepartmentIsolation.mockResolvedValue(false)
|
|
|
|
const request = new NextRequest('http://localhost/api/departments?id=dept-1', {
|
|
method: 'DELETE',
|
|
})
|
|
|
|
const response = await DELETE(request)
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('当前许可证未包含部门隔离功能')
|
|
expect(prisma.department.findUnique).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('DELETE 普通管理员不能删除部门', async () => {
|
|
prisma.user.findUnique.mockResolvedValue({ isSuperAdmin: false })
|
|
|
|
const request = new NextRequest('http://localhost/api/departments?id=dept-1', {
|
|
method: 'DELETE',
|
|
})
|
|
|
|
const response = await DELETE(request)
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('最高权限')
|
|
expect(canUseDepartmentIsolation).not.toHaveBeenCalled()
|
|
expect(prisma.department.findUnique).not.toHaveBeenCalled()
|
|
})
|
|
})
|