154 lines
4.1 KiB
TypeScript
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: '设计部-' } } },
|
|
]),
|
|
},
|
|
])
|
|
})
|
|
})
|