130 lines
3.8 KiB
TypeScript
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')
|
|
})
|
|
})
|