gongxiangp2/lib/__tests__/task-detail-change-request-routes.test.ts

124 lines
4.8 KiB
TypeScript

/** @jest-environment node */
import { getServerSession } from 'next-auth'
import {
GET as listChanges,
POST as submitChange,
} from '@/app/api/materials/[id]/assets/change-requests/route'
import { GET as getChange } from '@/app/api/task-detail-change-requests/[id]/route'
import { POST as decideChange } from '@/app/api/task-detail-change-requests/[id]/decision/route'
import {
decideTaskDetailChange,
getTaskDetailChangeRequest,
listTaskDetailChanges,
submitTaskDetailChange,
TaskDetailChangeApprovalError,
} from '@/lib/task-detail-change-approval'
jest.mock('next-auth', () => ({ getServerSession: jest.fn() }))
jest.mock('@/lib/auth', () => ({ authOptions: {} }))
jest.mock('@/lib/task-detail-change-approval', () => ({
TaskDetailChangeApprovalError: class TaskDetailChangeApprovalError extends Error {
statusCode: number
constructor(message: string, statusCode = 400) {
super(message)
this.statusCode = statusCode
}
},
decideTaskDetailChange: jest.fn(),
getTaskDetailChangeRequest: jest.fn(),
listTaskDetailChanges: jest.fn(),
submitTaskDetailChange: jest.fn(),
}))
const actor = { id: 'user-1', role: 'USER', isSuperAdmin: false }
function requestWith(body: unknown) {
return { json: async () => body } as any
}
describe('任务详情图片变更审批 API', () => {
beforeEach(() => {
jest.clearAllMocks()
})
test('四个入口都拒绝未登录请求', async () => {
;(getServerSession as jest.Mock).mockResolvedValue(null)
const responses = await Promise.all([
listChanges({} as any, { params: { id: 'material-1' } }),
submitChange(requestWith({ operations: [] }), { params: { id: 'material-1' } }),
getChange({} as any, { params: { id: 'request-1' } }),
decideChange(requestWith({ decision: 'approve' }), { params: { id: 'request-1' } }),
])
expect(responses.map((response) => response.status)).toEqual([401, 401, 401, 401])
expect(submitTaskDetailChange).not.toHaveBeenCalled()
expect(decideTaskDetailChange).not.toHaveBeenCalled()
})
test('提交和列表使用当前登录人并返回审批结果', async () => {
;(getServerSession as jest.Mock).mockResolvedValue({ user: actor })
;(submitTaskDetailChange as jest.Mock).mockResolvedValue({
mode: 'pending_approval',
request: { id: 'request-1', status: 'pending_manager_approval' },
})
;(listTaskDetailChanges as jest.Mock).mockResolvedValue([{ id: 'request-1' }])
const operations = [{ kind: 'delete', assetId: 'asset-1' }]
const submitted = await submitChange(requestWith({ operations }), { params: { id: 'material-1' } })
const listed = await listChanges({} as any, { params: { id: 'material-1' } })
expect(submitted.status).toBe(200)
await expect(submitted.json()).resolves.toMatchObject({
success: true,
mode: 'pending_approval',
request: { id: 'request-1' },
})
expect(submitTaskDetailChange).toHaveBeenCalledWith('material-1', actor, operations)
expect(listTaskDetailChanges).toHaveBeenCalledWith('material-1', actor)
await expect(listed.json()).resolves.toEqual({ success: true, data: [{ id: 'request-1' }] })
})
test('详情与批准接口透传审批服务结果', async () => {
;(getServerSession as jest.Mock).mockResolvedValue({ user: actor })
;(getTaskDetailChangeRequest as jest.Mock).mockResolvedValue({ id: 'request-1', canDecide: true })
;(decideTaskDetailChange as jest.Mock).mockResolvedValue({ status: 'applied' })
const detail = await getChange({} as any, { params: { id: 'request-1' } })
const decision = await decideChange(
requestWith({ decision: 'approve' }),
{ params: { id: 'request-1' } },
)
await expect(detail.json()).resolves.toEqual({ success: true, data: { id: 'request-1', canDecide: true } })
await expect(decision.json()).resolves.toEqual({ success: true, data: { status: 'applied' } })
expect(decideTaskDetailChange).toHaveBeenCalledWith('request-1', actor, 'approve')
})
test('非法决定在路由层返回 400', async () => {
;(getServerSession as jest.Mock).mockResolvedValue({ user: actor })
const response = await decideChange(
requestWith({ decision: 'later' }),
{ params: { id: 'request-1' } },
)
expect(response.status).toBe(400)
expect(decideTaskDetailChange).not.toHaveBeenCalled()
})
test('审批业务错误保留状态码和用户可读文案', async () => {
;(getServerSession as jest.Mock).mockResolvedValue({ user: actor })
;(getTaskDetailChangeRequest as jest.Mock).mockRejectedValue(
new TaskDetailChangeApprovalError('您无权查看这条图片变更申请', 403),
)
const response = await getChange({} as any, { params: { id: 'request-1' } })
expect(response.status).toBe(403)
await expect(response.json()).resolves.toEqual({ success: false, error: '您无权查看这条图片变更申请' })
})
})