/** @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, 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') }) })