import { describe, expect, it } from 'vitest'; import { createVideoFirstFrameOperations } from '@/pages/ImageCanvas/video-first-frame'; import { designFormFixture, designValuesFixture, designWorkspaceFixture, } from '../fixtures/design-workspace-v2'; import type { DesignAsset } from '../../shared/image-workspace'; const imageAsset: DesignAsset = { assetId: 'asset-first-frame', workspaceId: 'workspace-1', role: 'uploaded', mediaType: 'image', mimeType: 'image/png', width: 720, height: 1280, durationMilliseconds: null, generationTaskId: null, createdAt: '2026-09-16T00:00:00Z', contentPath: '/api/design/assets/asset-first-frame/content', }; describe('video first-frame binding', () => { it('adds an explicit first-frame reference without deleting the asset', () => { const workspace = designWorkspaceFixture(); const result = createVideoFirstFrameOperations(workspace, imageAsset); expect(result.nextPrompt).toContain('@图片1'); expect(result.operations).toEqual(expect.arrayContaining([ { kind: 'set', path: 'video.first_frame_asset_id', value: imageAsset.assetId }, expect.objectContaining({ kind: 'set', path: 'references' }), expect.objectContaining({ kind: 'set', path: 'content.concept' }), ])); const referencesOperation = result.operations.find((operation) => operation.path === 'references'); expect(referencesOperation).toMatchObject({ value: [expect.objectContaining({ asset_id: imageAsset.assetId, role: 'first_frame' })], }); }); it('promotes an existing reference and demotes the old first frame in place', () => { const values = structuredClone(designValuesFixture); values.intent.media = 'video'; values.references = [ { id: 'reference-old', asset_id: 'asset-old', asset_revision: null, role: 'first_frame', preserve: [], adapt: [], do_not_copy: [], reviewed_observations: [], }, { id: 'reference-next', asset_id: imageAsset.assetId, asset_revision: null, role: 'inspiration', preserve: [], adapt: [], do_not_copy: [], reviewed_observations: [], }, ]; values.video.first_frame_asset_id = 'asset-old'; values.content.concept = '参考 @图片1 和 @图片2 的画面'; const workspace = designWorkspaceFixture({ form: designFormFixture({ specification: { schema_version: 1, values, field_decisions: {} }, }), }); const result = createVideoFirstFrameOperations(workspace, imageAsset); const referencesOperation = result.operations.find((operation) => operation.path === 'references'); expect(referencesOperation).toMatchObject({ value: [ expect.objectContaining({ asset_id: 'asset-old', role: 'inspiration' }), expect.objectContaining({ asset_id: imageAsset.assetId, role: 'first_frame' }), ], }); expect(result.operations).toContainEqual({ kind: 'set', path: 'video.first_frame_asset_id', value: imageAsset.assetId, }); expect(result.nextPrompt).toBe('参考 @图片1 和 @图片2 的画面'); }); });