gongxiangp2/lib/__tests__/product-package-init-route.test.ts

258 lines
7.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @jest-environment node */
import { NextRequest } from 'next/server'
import { getServerSession } from 'next-auth'
import { POST } from '@/app/api/materials/upload/product-package/init/route'
import { prisma } from '@/lib/prisma'
import { isTaskNoExists, purgeDeletedMaterialsByTaskNo, validateTaskNo } from '@/lib/product-package'
jest.mock('next-auth', () => ({
getServerSession: jest.fn(),
}))
jest.mock('@/lib/auth', () => ({
authOptions: {},
}))
jest.mock('@/lib/prisma', () => ({
prisma: {
material: {
create: jest.fn(),
},
user: {
findFirst: jest.fn(),
findUnique: jest.fn(),
},
},
}))
jest.mock('@/lib/product-package', () => ({
validateTaskNo: jest.fn(() => true),
isTaskNoExists: jest.fn(() => false),
purgeDeletedMaterialsByTaskNo: jest.fn(() => Promise.resolve({ deletedMaterials: 0, deletedFiles: 0, failedFiles: 0 })),
}))
jest.mock('@/lib/material-query', () => ({
INCOMPLETE_SHELL_CREATE_DATA: {
isIncompleteShell: true,
},
}))
describe('product-package init route', () => {
beforeEach(() => {
jest.clearAllMocks()
;(getServerSession as jest.Mock).mockResolvedValue({
// 贴近真实登录态:lib/auth.ts 的 session 回调只写入 id/email/role 等字段,
// 从不写入 username 或 realName。此前实现误读这两个字段,一路兜底把邮箱
// 存成了作者名,而旧测试恰好给了一个含 username 的理想化 session,把问题掩盖了。
user: {
id: 'user-1',
email: 'tester@example.com',
},
})
;(prisma.material.create as jest.Mock).mockResolvedValue({
id: 'material-1',
})
;(prisma.user.findFirst as jest.Mock).mockResolvedValue({
id: 'requester-1',
username: 'operator',
realName: '运营甲',
})
;(prisma.user.findUnique as jest.Mock).mockResolvedValue({
username: 'tester',
})
})
test('未填写出图方式时应拒绝初始化任务详情上传', async () => {
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
sceneName: '客厅',
taskDetailRequesterUserId: 'requester-1',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
const body = await response.json()
expect(response.status).toBe(400)
expect(body.success).toBe(false)
expect(body.error).toContain('出图方式')
expect(prisma.material.create).not.toHaveBeenCalled()
})
test('非法出图方式应返回 400', async () => {
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
taskDetailSourceType: '照片',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
const body = await response.json()
expect(response.status).toBe(400)
expect(body.error).toContain('出图方式')
expect(prisma.material.create).not.toHaveBeenCalled()
})
test('新品私密组合会在初始化阶段被拒绝', async () => {
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
taskDetailSourceType: '渲染',
taskDetailDemandType: '新品',
taskDetailPrivate: true,
taskDetailRequesterUserId: 'requester-1',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
const body = await response.json()
expect(response.status).toBe(400)
expect(body.error).toBe('仅优化需求支持私密上传')
expect(prisma.material.create).not.toHaveBeenCalled()
})
test('优化私密会原样持久化', async () => {
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
taskNo: 'TASK202604230001',
taskDetailSourceType: '渲染',
taskDetailDemandType: '优化',
taskDetailPrivate: true,
taskDetailRequesterUserId: 'requester-1',
taskDetailRequesterName: '伪造姓名',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
expect(response.status).toBe(200)
expect(validateTaskNo).toHaveBeenCalledWith('TASK202604230001')
expect(isTaskNoExists).toHaveBeenCalledWith('TASK202604230001')
expect(purgeDeletedMaterialsByTaskNo).not.toHaveBeenCalled()
expect(prisma.material.create).toHaveBeenCalledWith({
data: expect.objectContaining({
taskDetailSourceType: '渲染',
taskDetailDemandType: '优化',
taskDetailPrivate: true,
taskDetailRequesterUserId: 'requester-1',
taskDetailRequesterName: '运营甲',
// 作者名必须取自数据库中的用户名,而不是登录态里并不存在的字段,
// 更不能兜底成邮箱
authorName: 'tester',
isIncompleteShell: true,
}),
})
expect(prisma.user.findUnique).toHaveBeenCalledWith({
where: { id: 'user-1' },
select: { username: true },
})
})
test('缺省需求类型和私密时回填新品公开', async () => {
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
taskDetailSourceType: '渲染',
taskDetailRequesterUserId: 'requester-1',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
expect(response.status).toBe(200)
expect(prisma.material.create).toHaveBeenCalledWith({
data: expect.objectContaining({
taskDetailDemandType: '新品',
taskDetailPrivate: false,
}),
})
})
test('未选择需求运营人员时应返回 400', async () => {
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
const body = await response.json()
expect(response.status).toBe(400)
expect(body.error).toBe('请选择需求运营人员')
expect(prisma.user.findFirst).not.toHaveBeenCalled()
expect(prisma.material.create).not.toHaveBeenCalled()
})
test('需求运营人员不存在或已停用时应返回 400', async () => {
;(prisma.user.findFirst as jest.Mock).mockResolvedValue(null)
const request = new NextRequest('http://localhost/api/materials/upload/product-package/init', {
method: 'POST',
body: JSON.stringify({
productModel: 'SPU-001',
categoryName: '旗舰店',
taskDetailRequesterUserId: 'inactive-user',
}),
headers: {
'Content-Type': 'application/json',
},
})
const response = await POST(request)
const body = await response.json()
expect(response.status).toBe(400)
expect(body.error).toContain('不存在或已停用')
expect(prisma.user.findFirst).toHaveBeenCalledWith({
where: {
id: 'inactive-user',
isActive: true,
status: 'active',
},
select: {
id: true,
username: true,
realName: true,
},
})
expect(prisma.material.create).not.toHaveBeenCalled()
})
})