90 lines
3.1 KiB
TypeScript
90 lines
3.1 KiB
TypeScript
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 的画面');
|
|
});
|
|
});
|