2026-06-03 18:41:52 +08:00

154 lines
4.1 KiB
TypeScript

import { GET } from '../route'
export {}
jest.mock('@/lib/auth', () => ({
authOptions: {},
}))
jest.mock('next-auth', () => ({
getServerSession: jest.fn(),
}))
jest.mock('@/lib/license', () => ({
planDepartmentScopeWithPaidCore: jest.fn(),
}))
jest.mock('@/lib/prisma', () => ({
prisma: {
material: {
count: jest.fn(),
},
user: {
findUnique: jest.fn(),
},
department: {
findMany: jest.fn(),
},
$queryRaw: jest.fn(),
},
}))
const { getServerSession } = require('next-auth')
const { prisma } = require('@/lib/prisma')
const { planDepartmentScopeWithPaidCore } = require('@/lib/license')
describe('GET /api/materials/stats', () => {
beforeEach(() => {
jest.resetAllMocks()
prisma.user.findUnique.mockResolvedValue({
id: 'user-1',
role: 'USER',
isSuperAdmin: false,
isActive: true,
canDownload: true,
department: '设计部',
managedDepartment: null,
})
prisma.department.findMany.mockResolvedValue([
{ name: '设计部' },
{ name: '设计部-建模组' },
{ name: '运营部' },
])
planDepartmentScopeWithPaidCore.mockResolvedValue({
valid: true,
scopedDepartments: ['设计部', '设计部-建模组'],
withinScope: true,
})
})
it('未登录时不暴露素材总量和月份趋势', async () => {
getServerSession.mockResolvedValue(null)
const response = await GET()
const data = await response.json()
expect(response.status).toBe(401)
expect(data.error).toBe('请先登录')
expect(prisma.material.count).not.toHaveBeenCalled()
})
it('已登录时返回素材统计', async () => {
getServerSession.mockResolvedValue({ user: { id: 'user-1' } })
prisma.material.count.mockResolvedValue(12)
prisma.$queryRaw.mockResolvedValue([
{ year: 2026, month: 6, count: BigInt(5) },
])
const response = await GET()
const data = await response.json()
expect(response.status).toBe(200)
expect(data.total).toBe(12)
expect(data.months).toEqual([
{ value: '2026-06', label: '2026年6月', count: 5 },
])
expect(prisma.material.count).toHaveBeenCalledWith({
where: {
AND: [
{ deletedAt: null },
{
OR: [
{ userId: 'user-1' },
{ ownerType: 'USER', ownerId: 'user-1' },
],
},
],
},
})
})
it('禁用用户即使有旧会话也不能读取统计', async () => {
getServerSession.mockResolvedValue({ user: { id: 'user-1' } })
prisma.user.findUnique.mockResolvedValueOnce({
id: 'user-1',
role: 'USER',
isSuperAdmin: false,
isActive: false,
canDownload: true,
department: '设计部',
managedDepartment: null,
})
const response = await GET()
const data = await response.json()
expect(response.status).toBe(403)
expect(data.error).toContain('账号不可用')
expect(prisma.material.count).not.toHaveBeenCalled()
expect(prisma.$queryRaw).not.toHaveBeenCalled()
})
it('部门管理员统计只覆盖自己和管理部门范围内的素材', async () => {
getServerSession.mockResolvedValue({ user: { id: 'manager-1', role: 'ADMIN' } })
prisma.user.findUnique.mockResolvedValueOnce({
id: 'manager-1',
role: 'ADMIN',
isSuperAdmin: false,
isActive: true,
canDownload: true,
department: '设计部',
managedDepartment: '设计部',
})
prisma.material.count.mockResolvedValue(3)
prisma.$queryRaw.mockResolvedValue([
{ year: 2026, month: 5, count: BigInt(3) },
])
const response = await GET()
expect(response.status).toBe(200)
expect(prisma.material.count.mock.calls[0][0].where.AND).toEqual([
{ deletedAt: null },
{
OR: expect.arrayContaining([
{ userId: 'manager-1' },
{ ownerType: 'USER', ownerId: 'manager-1' },
{ user: { department: { in: expect.arrayContaining(['设计部', '设计部-建模组']) } } },
{ user: { department: { startsWith: '设计部-' } } },
]),
},
])
})
})