59 lines
3.3 KiB
TypeScript

/** @jest-environment node */
import { NextRequest } from 'next/server'
import { getServerSession } from 'next-auth'
import { resolveBrandCenterAccessForUser } from '@/lib/brand-center-access'
import { isSuperAdmin } from '@/lib/department-permission'
import { getTeamFunctions, saveTeamFunction, TeamFunctionError } from '@/lib/team-functions'
import { GET, PUT } from './route'
jest.mock('next-auth', () => ({ getServerSession: jest.fn() }))
jest.mock('@/lib/auth', () => ({ authOptions: {} }))
jest.mock('@/lib/brand-center-access', () => ({ resolveBrandCenterAccessForUser: jest.fn() }))
jest.mock('@/lib/department-permission', () => ({ isSuperAdmin: jest.fn() }))
jest.mock('@/lib/team-functions', () => ({ ...jest.requireActual('@/lib/team-functions'), getTeamFunctions: jest.fn(), saveTeamFunction: jest.fn() }))
jest.mock('@/lib/prisma', () => ({ prisma: {} }))
const input = { organizationUnitId: 'team', revision: 0, leadEmployeeProfileId: null, description: '说明', branches: [] }
const request = (body: unknown) => new NextRequest('http://local/api/organization/team-functions', { method: 'PUT', body: JSON.stringify(body) })
beforeEach(() => {
jest.clearAllMocks()
;(getServerSession as jest.Mock).mockResolvedValue({ user: { id: 'actor', role: 'USER' } })
;(resolveBrandCenterAccessForUser as jest.Mock).mockResolvedValue(true)
;(isSuperAdmin as jest.Mock).mockResolvedValue(false)
;(getTeamFunctions as jest.Mock).mockResolvedValue({ teams: [], canEdit: false })
;(saveTeamFunction as jest.Mock).mockResolvedValue({ revision: 1 })
})
test('品牌中心成员可读,不取得维护权限或候选人员', async () => {
const response = await GET()
expect(response.status).toBe(200)
expect(response.headers.get('Cache-Control')).toBe('private, no-store')
expect(getTeamFunctions).toHaveBeenCalledWith(false)
})
test('未登录及非品牌中心成员拒绝读取', async () => {
;(getServerSession as jest.Mock).mockResolvedValue(null)
expect((await GET()).status).toBe(403)
;(getServerSession as jest.Mock).mockResolvedValue({ user: { id: 'actor' } })
;(resolveBrandCenterAccessForUser as jest.Mock).mockResolvedValue(false)
expect((await GET()).status).toBe(403)
expect(getTeamFunctions).not.toHaveBeenCalled()
})
test('客户端提交的管理员身份不能绕过数据库检查', async () => {
expect((await PUT(request({ ...input, isSuperAdmin: true }))).status).toBe(403)
expect(saveTeamFunction).not.toHaveBeenCalled()
})
test('超级管理员使用服务端身份保存', async () => {
;(isSuperAdmin as jest.Mock).mockResolvedValue(true)
expect((await PUT(request(input))).status).toBe(200)
expect(saveTeamFunction).toHaveBeenCalledWith(input, 'actor')
})
test('空分组、超长条目及错误修订号拒绝写入', async () => {
;(isSuperAdmin as jest.Mock).mockResolvedValue(true)
for (const body of [{ ...input, revision: -1 }, { ...input, branches: [{ label: '', items: ['职责'] }] }, { ...input, description: 'x'.repeat(2001) }]) {
expect((await PUT(request(body))).status).toBe(400)
}
expect(saveTeamFunction).not.toHaveBeenCalled()
})
test('版本冲突返回可恢复的错误', async () => {
;(isSuperAdmin as jest.Mock).mockResolvedValue(true)
;(saveTeamFunction as jest.Mock).mockRejectedValue(new TeamFunctionError('配置已更新', 409))
expect((await PUT(request(input))).status).toBe(409)
})