2026-05-25 15:36:51 +08:00

130 lines
3.8 KiB
TypeScript

import { NextRequest } from 'next/server'
import { GET } from '../route'
jest.mock('@/lib/auth', () => ({
authOptions: {},
}))
jest.mock('next-auth', () => ({
getServerSession: jest.fn(),
}))
jest.mock('@/lib/prisma', () => ({
prisma: {
material: {
findFirst: jest.fn(),
},
materialShareToken: {
findMany: jest.fn(),
},
user: {
findUnique: jest.fn(),
},
},
}))
const { getServerSession } = require('next-auth')
const { prisma } = require('@/lib/prisma')
describe('GET /api/materials/share/tokens', () => {
beforeEach(() => {
jest.clearAllMocks()
})
it('未登录时拒绝查看分享链接列表', async () => {
getServerSession.mockResolvedValue(null)
const response = await GET(
new NextRequest('http://localhost/api/materials/share/tokens?materialId=material-1')
)
const data = await response.json()
expect(response.status).toBe(401)
expect(data.error).toBe('请先登录')
expect(prisma.material.findFirst).not.toHaveBeenCalled()
})
it('无关普通用户不能查看别人的素材分享链接', async () => {
getServerSession.mockResolvedValue({ user: { id: 'user-3', role: 'USER' } })
prisma.user.findUnique.mockResolvedValue({ id: 'user-3', role: 'USER', isSuperAdmin: false })
prisma.material.findFirst.mockResolvedValue({
id: 'material-1',
userId: 'user-1',
ownerType: 'USER',
ownerId: 'user-1',
createdByUserId: 'user-1',
})
const response = await GET(
new NextRequest('http://localhost/api/materials/share/tokens?materialId=material-1')
)
const data = await response.json()
expect(response.status).toBe(403)
expect(data.error).toBe('无权查看该素材的分享链接')
expect(prisma.materialShareToken.findMany).not.toHaveBeenCalled()
})
it('素材负责人可以查看分享链接状态,但不会返回 token 明文或 hash', async () => {
getServerSession.mockResolvedValue({ user: { id: 'user-1', role: 'USER' } })
prisma.user.findUnique.mockResolvedValue({ id: 'user-1', role: 'USER', isSuperAdmin: false })
prisma.material.findFirst.mockResolvedValue({
id: 'material-1',
userId: 'user-1',
ownerType: 'USER',
ownerId: 'user-1',
createdByUserId: 'user-1',
})
prisma.materialShareToken.findMany.mockResolvedValue([
{
id: 'token-1',
materialId: 'material-1',
createdByUserId: 'user-1',
createdAt: new Date('2026-05-24T00:00:00.000Z'),
expiresAt: new Date('2999-01-01T00:00:00.000Z'),
revokedAt: null,
createdBy: {
id: 'user-1',
username: 'owner',
email: 'owner@example.com',
realName: null,
},
},
{
id: 'token-2',
materialId: 'material-1',
createdByUserId: 'user-1',
createdAt: new Date('2026-05-23T00:00:00.000Z'),
expiresAt: new Date('2026-05-30T00:00:00.000Z'),
revokedAt: new Date('2026-05-24T01:00:00.000Z'),
createdBy: {
id: 'user-1',
username: 'owner',
email: 'owner@example.com',
realName: '负责人',
},
},
])
const response = await GET(
new NextRequest('http://localhost/api/materials/share/tokens?materialId=material-1')
)
const data = await response.json()
expect(response.status).toBe(200)
expect(data.tokens).toHaveLength(2)
expect(data.tokens[0]).toEqual(expect.objectContaining({
id: 'token-1',
status: 'active',
createdByName: 'owner',
}))
expect(data.tokens[1]).toEqual(expect.objectContaining({
id: 'token-2',
status: 'revoked',
createdByName: '负责人',
}))
expect(JSON.stringify(data)).not.toContain('tokenHash')
expect(JSON.stringify(data)).not.toContain('share-token')
})
})