/** @jest-environment node */ import { prisma } from '@/lib/prisma' import { inspectTaskMaterialCompletionAfterError } from '@/lib/task-material-completion-safety' jest.mock('@/lib/prisma', () => ({ prisma: { material: { findUnique: jest.fn() }, }, })) describe('task material completion acknowledgement safety', () => { beforeEach(() => { jest.clearAllMocks() }) test.each([ ['processing', 'processing'], ['failed', 'other'], [null, 'other'], ] as const)('数据库状态 %s 映射为 %s', async (taskStatus, expectedState) => { ;(prisma.material.findUnique as jest.Mock).mockResolvedValue({ taskStatus, previewUrl: '', zipFilePath: '', assets: [], }) await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toMatchObject({ state: expectedState, }) }) test('只有预览、ZIP 与两类资产证据齐全才映射为 completed', async () => { ;(prisma.material.findUnique as jest.Mock).mockResolvedValue({ taskStatus: 'completed', previewUrl: 'https://s3.example/preview.webp', zipFilePath: 'materials/source.zip', assets: [{ assetType: 'preview' }, { assetType: 'zip' }], }) await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toMatchObject({ state: 'completed', }) }) test.each([ ['', 'materials/source.zip', [{ assetType: 'preview' }, { assetType: 'zip' }]], ['https://s3.example/preview.webp', '', [{ assetType: 'preview' }, { assetType: 'zip' }]], ['https://s3.example/preview.webp', 'materials/source.zip', [{ assetType: 'preview' }]], ])('已完成但证据不全时映射为 completed_incomplete', async (previewUrl, zipFilePath, assets) => { ;(prisma.material.findUnique as jest.Mock).mockResolvedValue({ taskStatus: 'completed', previewUrl, zipFilePath, assets, }) await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toMatchObject({ state: 'completed_incomplete', }) }) test('查询失败时返回 unknown,调用方必须保留文件', async () => { const error = new Error('database unavailable') ;(prisma.material.findUnique as jest.Mock).mockRejectedValue(error) await expect(inspectTaskMaterialCompletionAfterError('material-1')).resolves.toEqual({ state: 'unknown', error, }) }) })