gongxiangp2/lib/__tests__/task-page-upload-routes.test.ts

108 lines
3.9 KiB
TypeScript
Raw 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 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 } }),
});
}