108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
/** @jest-environment node */
|
||
|
||
import { NextRequest } from 'next/server';
|
||
import { getServerSession } from 'next-auth';
|
||
|
||
import { POST as initTaskPage } from '@/app/api/materials/upload/task-page/init/route';
|
||
import { POST as completeTaskPage } from '@/app/api/materials/upload/task-page/complete/route';
|
||
import { prisma } from '@/lib/prisma';
|
||
import { completeTaskImageMaterial } from '@/lib/task-image-material-completion';
|
||
|
||
jest.mock('next-auth', () => ({ getServerSession: jest.fn() }));
|
||
jest.mock('@/lib/auth', () => ({ authOptions: {} }));
|
||
jest.mock('@/lib/prisma', () => ({
|
||
prisma: {
|
||
user: { findUnique: jest.fn() },
|
||
material: { create: jest.fn() },
|
||
},
|
||
}));
|
||
jest.mock('@/lib/task-image-material-completion', () => ({
|
||
completeTaskImageMaterial: jest.fn(),
|
||
}));
|
||
|
||
describe('任务-页面上传接口', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks();
|
||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||
(getServerSession as jest.Mock).mockResolvedValue({ user: { id: 'user-1' } });
|
||
(prisma.user.findUnique as jest.Mock).mockResolvedValue({ username: '张三' });
|
||
(prisma.material.create as jest.Mock).mockResolvedValue({ id: 'material-1' });
|
||
(completeTaskImageMaterial as jest.Mock).mockResolvedValue({ materialId: 'material-1' });
|
||
});
|
||
|
||
afterEach(() => {
|
||
jest.restoreAllMocks();
|
||
});
|
||
|
||
test('初始化接口应返回顶层 materialId,并标记为 uploading', async () => {
|
||
const response = await initTaskPage(
|
||
new NextRequest('http://localhost/api/materials/upload/task-page/init', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
productModel: 'SJ0371',
|
||
categoryName: '索菲亚',
|
||
sceneName: '书房',
|
||
}),
|
||
}),
|
||
);
|
||
const body = await response.json();
|
||
|
||
expect(response.status).toBe(200);
|
||
expect(body).toEqual({ success: true, materialId: 'material-1' });
|
||
expect(prisma.material.create).toHaveBeenCalledWith(
|
||
expect.objectContaining({
|
||
data: expect.objectContaining({
|
||
materialType: '任务-页面',
|
||
taskStatus: 'uploading',
|
||
isIncompleteShell: true,
|
||
}),
|
||
}),
|
||
);
|
||
});
|
||
|
||
test('完成接口把固定素材类型、用户和原始资产交给共享安全状态机', async () => {
|
||
const assets = [{ uploadId: 'upload-1', fileName: 'page.jpg', fileSize: 10 }];
|
||
const response = await completeTaskPage(makeCompleteRequest(assets));
|
||
|
||
expect(response.status).toBe(200);
|
||
expect(completeTaskImageMaterial).toHaveBeenCalledWith({
|
||
materialId: 'material-1',
|
||
userId: 'user-1',
|
||
materialType: '任务-页面',
|
||
fallbackProductModel: 'task-page',
|
||
assets,
|
||
taskNo: undefined,
|
||
dingtalkApprovalNo: undefined,
|
||
});
|
||
});
|
||
|
||
test('共享状态机返回 alreadyCompleted 时保持幂等成功', async () => {
|
||
(completeTaskImageMaterial as jest.Mock).mockResolvedValue({
|
||
materialId: 'material-1',
|
||
alreadyCompleted: true,
|
||
});
|
||
const response = await completeTaskPage(makeCompleteRequest([]));
|
||
const body = await response.json();
|
||
|
||
expect(response.status).toBe(200);
|
||
expect(body).toMatchObject({ success: true, alreadyCompleted: true });
|
||
});
|
||
|
||
test('共享状态机的限额和并发错误状态应原样返回', async () => {
|
||
(completeTaskImageMaterial as jest.Mock).mockRejectedValue(
|
||
Object.assign(new Error('图片超过限制'), { status: 413 }),
|
||
);
|
||
const response = await completeTaskPage(makeCompleteRequest([]));
|
||
expect(response.status).toBe(413);
|
||
});
|
||
});
|
||
|
||
function makeCompleteRequest(assets: Array<{ uploadId: string; fileName: string; fileSize: number }>) {
|
||
return new NextRequest('http://localhost/api/materials/upload/task-page/complete', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ materialId: 'material-1', assets: { main: assets } }),
|
||
});
|
||
}
|