import { afterEach, describe, expect, it, vi } from 'vitest' import { projectAssetsApi } from '@/features/project-assets/api' import type { ProjectAsset } from '@/features/project-assets/types' const asset: ProjectAsset = { id: 'asset-db-1', projectId: 'project-db-1', name: '雨夜街道', type: 'image', category: 'scene', mimeType: 'image/png', extension: 'png', size: 2048, publicUrl: '/storage/project/scene.png', metadata: { originalName: 'scene.png' }, createdAt: '2026-09-21T00:00:00Z', updatedAt: '2026-09-21T00:00:00Z' } afterEach(() => vi.unstubAllGlobals()) describe('项目资产 API', () => { it('通过单个全局接口读取全部项目素材', async () => { const globalAsset = { ...asset, project: { id: 'project-db-1', title: '记忆当铺', topic: '记忆交易', status: 'completed' } } const fetcher = vi.fn().mockResolvedValue(new Response(JSON.stringify({ data: [globalAsset] }))) vi.stubGlobal('fetch', fetcher) await expect(projectAssetsApi.listAll()).resolves.toEqual([globalAsset]) expect(fetcher).toHaveBeenCalledOnce() expect(fetcher).toHaveBeenCalledWith('/api/assets', expect.objectContaining({ method: 'GET' })) }) it('使用 multipart 上传文件,不手工设置 Content-Type', async () => { const fetcher = vi .fn() .mockResolvedValue(new Response(JSON.stringify({ data: asset }), { status: 201 })) vi.stubGlobal('fetch', fetcher) const file = new File(['image'], 'scene.png', { type: 'image/png' }) await expect( projectAssetsApi.upload('project-db-1', { file, name: '雨夜街道', category: 'scene' }) ).resolves.toEqual(asset) const [url, init] = fetcher.mock.calls[0]! expect(url).toBe('/api/projects/project-db-1/assets') expect(init?.method).toBe('POST') expect(init?.headers).toEqual({ Accept: 'application/json' }) expect(init?.body).toBeInstanceOf(FormData) const body = init?.body as FormData expect(body.get('file')).toBe(file) expect(body.get('name')).toBe('雨夜街道') expect(body.get('category')).toBe('scene') }) it('按正式项目和素材 ID 读取、编辑及删除', async () => { const fetcher = vi .fn() .mockImplementation(async () => new Response(JSON.stringify({ data: asset }))) vi.stubGlobal('fetch', fetcher) await projectAssetsApi.list('project/db') await projectAssetsApi.get('project/db', 'asset/db') await projectAssetsApi.update('project/db', 'asset/db', { name: '新名称', category: 'reference' }) await projectAssetsApi.remove('project/db', 'asset/db') expect(fetcher.mock.calls.map(([url, init]) => [url, init?.method ?? 'GET'])).toEqual([ ['/api/projects/project%2Fdb/assets', 'GET'], ['/api/projects/project%2Fdb/assets/asset%2Fdb', 'GET'], ['/api/projects/project%2Fdb/assets/asset%2Fdb', 'PUT'], ['/api/projects/project%2Fdb/assets/asset%2Fdb', 'DELETE'] ]) expect(fetcher.mock.calls[2]?.[1]?.body).toBe(JSON.stringify({ name: '新名称', category: 'reference' })) }) })