124 lines
4.1 KiB
TypeScript
124 lines
4.1 KiB
TypeScript
/** @jest-environment node */
|
|
|
|
import { getServerSession } from 'next-auth'
|
|
import { POST } from '@/app/api/dingtalk/complete-profile/route'
|
|
import { prisma } from '@/lib/prisma'
|
|
import { verifyDingtalkProfileToken } from '@/lib/dingtalk-profile-token'
|
|
|
|
jest.mock('next-auth', () => ({
|
|
getServerSession: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/auth', () => ({ authOptions: {} }))
|
|
|
|
jest.mock('@/lib/dingtalk-profile-token', () => ({
|
|
getDingtalkProfileCookieCandidates: jest.fn(() => ['dingtalk-profile-token']),
|
|
getDingtalkProfileCookiePath: jest.fn(() => '/api/dingtalk/complete-profile'),
|
|
verifyDingtalkProfileToken: jest.fn().mockResolvedValue(null),
|
|
}))
|
|
|
|
jest.mock('@/lib/prisma', () => ({
|
|
prisma: {
|
|
user: {
|
|
findUnique: jest.fn(),
|
|
update: jest.fn(),
|
|
},
|
|
department: {
|
|
findUnique: jest.fn(),
|
|
},
|
|
},
|
|
}))
|
|
|
|
describe('dingtalk complete-profile route', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
;(verifyDingtalkProfileToken as jest.Mock).mockResolvedValue(null)
|
|
})
|
|
|
|
function createRequest(body: Record<string, unknown>, profileToken?: string) {
|
|
return {
|
|
json: jest.fn().mockResolvedValue(body),
|
|
cookies: {
|
|
get: jest.fn((name: string) =>
|
|
name === 'dingtalk-profile-token' && profileToken
|
|
? { value: profileToken }
|
|
: undefined,
|
|
),
|
|
},
|
|
} as any
|
|
}
|
|
|
|
test('匿名请求不得完善资料', async () => {
|
|
;(getServerSession as jest.Mock).mockResolvedValue(null)
|
|
|
|
const response = await POST(createRequest({ userId: 'user-1', department: '设计部' }))
|
|
|
|
expect(response.status).toBe(401)
|
|
expect(prisma.user.update).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('登录用户不得修改其他用户资料', async () => {
|
|
;(getServerSession as jest.Mock).mockResolvedValue({ user: { id: 'user-1' } })
|
|
|
|
const response = await POST(createRequest({ userId: 'user-2', department: '设计部' }))
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(prisma.user.findUnique).not.toHaveBeenCalled()
|
|
expect(prisma.user.update).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('仅更新会话本人并绑定真实部门', async () => {
|
|
;(getServerSession as jest.Mock).mockResolvedValue({ user: { id: 'user-1' } })
|
|
;(prisma.user.findUnique as jest.Mock).mockResolvedValue({ id: 'user-1' })
|
|
;(prisma.department.findUnique as jest.Mock).mockResolvedValue({ id: 'dept-1', name: '设计部' })
|
|
;(prisma.user.update as jest.Mock).mockResolvedValue({
|
|
id: 'user-1',
|
|
username: 'tester',
|
|
email: 'tester@example.com',
|
|
realName: '测试用户',
|
|
avatar: null,
|
|
role: 'USER',
|
|
department: '设计部',
|
|
isActive: false,
|
|
status: 'pending',
|
|
})
|
|
|
|
const response = await POST(createRequest({ userId: 'user-1', department: ' 设计部 ' }))
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(prisma.user.update).toHaveBeenCalledWith(expect.objectContaining({
|
|
where: { id: 'user-1' },
|
|
data: { department: '设计部', departmentId: 'dept-1' },
|
|
}))
|
|
})
|
|
|
|
test('首次登录用户可用短时资料凭证完善自己的部门', async () => {
|
|
;(getServerSession as jest.Mock).mockResolvedValue(null)
|
|
;(verifyDingtalkProfileToken as jest.Mock).mockResolvedValue('user-1')
|
|
;(prisma.user.findUnique as jest.Mock).mockResolvedValue({ id: 'user-1' })
|
|
;(prisma.department.findUnique as jest.Mock).mockResolvedValue({ id: 'dept-1', name: '设计部' })
|
|
;(prisma.user.update as jest.Mock).mockResolvedValue({
|
|
id: 'user-1',
|
|
username: 'tester',
|
|
email: 'tester@example.com',
|
|
realName: '测试用户',
|
|
avatar: null,
|
|
role: 'USER',
|
|
department: '设计部',
|
|
isActive: false,
|
|
status: 'pending',
|
|
})
|
|
|
|
const response = await POST(
|
|
createRequest({ userId: 'user-1', department: '设计部' }, 'signed-profile-token'),
|
|
)
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(verifyDingtalkProfileToken).toHaveBeenCalledWith('signed-profile-token')
|
|
expect(prisma.user.update).toHaveBeenCalledWith(expect.objectContaining({
|
|
where: { id: 'user-1' },
|
|
}))
|
|
expect(response.headers.get('set-cookie')).toContain('Max-Age=0')
|
|
})
|
|
})
|