fix(design): distinguish saved video settings from preparation needs
This commit is contained in:
@@ -123,7 +123,7 @@ test.describe('AI Design V2 workspace', () => {
|
||||
preserve_instructions: [],
|
||||
change_instructions: [],
|
||||
},
|
||||
video: { shots: [] },
|
||||
video: { shots: [], total_duration_seconds: null as number | null },
|
||||
output: {
|
||||
aspect_ratio: '3:4',
|
||||
orientation: 'portrait',
|
||||
@@ -186,11 +186,19 @@ test.describe('AI Design V2 workspace', () => {
|
||||
__designE2eAuthReady?: boolean;
|
||||
__designE2eProfileReady?: boolean;
|
||||
__designE2eCompleteTask?: () => void;
|
||||
__designE2eOpenIncompleteVideo?: () => void;
|
||||
__designE2eDownloadCount?: number;
|
||||
};
|
||||
e2eGlobal.__designE2eAuthReady = false;
|
||||
e2eGlobal.__designE2eProfileReady = false;
|
||||
e2eGlobal.__designE2eDownloadCount = 0;
|
||||
e2eGlobal.__designE2eOpenIncompleteVideo = () => {
|
||||
workspace.form.specification.values.intent.media = 'video';
|
||||
workspace.form.specification.values.video.total_duration_seconds = null;
|
||||
workspace.form.directionRevision += 1;
|
||||
workspace.form.specificationRevision += 1;
|
||||
workspace.workspace.specificationRevision = workspace.form.specificationRevision;
|
||||
};
|
||||
e2eGlobal.__designE2eCompleteTask = () => {
|
||||
workspace.tasks[0] = {
|
||||
...workspace.tasks[0],
|
||||
@@ -303,6 +311,9 @@ test.describe('AI Design V2 workspace', () => {
|
||||
if (operation.kind === 'set' && operation.path === 'output.orientation') {
|
||||
workspace.form.specification.values.output.orientation = String(operation.value ?? '');
|
||||
}
|
||||
if (operation.kind === 'set' && operation.path === 'video.total_duration_seconds') {
|
||||
workspace.form.specification.values.video.total_duration_seconds = Number(operation.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (command.input?.kind === 'chat' && command.input.message) {
|
||||
@@ -589,6 +600,20 @@ test.describe('AI Design V2 workspace', () => {
|
||||
expect(await app.evaluate(() => (
|
||||
globalThis as typeof globalThis & { __designE2eDownloadCount?: number }
|
||||
).__designE2eDownloadCount)).toBe(0);
|
||||
await app.evaluate(() => {
|
||||
(globalThis as typeof globalThis & { __designE2eOpenIncompleteVideo?: () => void })
|
||||
.__designE2eOpenIncompleteVideo?.();
|
||||
});
|
||||
await page.reload();
|
||||
const duration = page.getByRole('combobox', { name: '时长' });
|
||||
await expect(duration).toHaveValue('');
|
||||
await expect(page.getByRole('button', { name: '增加时长' })).toHaveCount(0);
|
||||
await expect(page.getByText('至少写一个视频画面。')).toHaveCount(0);
|
||||
await duration.selectOption('6');
|
||||
await expect(page.getByRole('button', { name: '增加时长' })).toBeEnabled();
|
||||
await page.reload();
|
||||
await expect(page.getByRole('combobox', { name: '时长' })).toHaveCount(0);
|
||||
await expect(page.getByText('6 秒', { exact: true })).toBeVisible();
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { DesignPlanHistory } from '@/pages/ImageCanvas/DesignPlanHistory';
|
||||
import { YouthCreationCard } from '@/pages/ImageCanvas/YouthCreationCard';
|
||||
import { useImageWorkspaceStore } from '@/stores/image-workspace';
|
||||
import type { DesignGenerationTask } from '../../shared/image-workspace';
|
||||
import type { DesignCompilationIssue, DesignGenerationTask } from '../../shared/image-workspace';
|
||||
import {
|
||||
designCapabilitiesFixture,
|
||||
designFormFixture,
|
||||
@@ -58,7 +58,7 @@ function taskFixture(overrides: Partial<DesignGenerationTask> = {}): DesignGener
|
||||
};
|
||||
}
|
||||
|
||||
function renderCard(workspace = designWorkspaceFixture()) {
|
||||
function renderCard(workspace = designWorkspaceFixture(), quoteBlockers: DesignCompilationIssue[] = []) {
|
||||
const actions = {
|
||||
applyFieldOperations: vi.fn().mockResolvedValue(workspace),
|
||||
prepareGeneration: vi.fn().mockResolvedValue(workspace),
|
||||
@@ -74,7 +74,7 @@ function renderCard(workspace = designWorkspaceFixture()) {
|
||||
render(
|
||||
<YouthCreationCard
|
||||
workspace={workspace}
|
||||
quoteBlockers={[]}
|
||||
quoteBlockers={quoteBlockers}
|
||||
generationAvailable
|
||||
generationOptions={designCapabilitiesFixture.generationOptions}
|
||||
onQuoteOffered={vi.fn()}
|
||||
@@ -123,6 +123,49 @@ describe('YouthCreationCard', () => {
|
||||
useImageWorkspaceStore.getState().reset();
|
||||
});
|
||||
|
||||
it('does not present a missing saved video duration as an already selected six seconds', () => {
|
||||
const workspace = referenceWorkspace();
|
||||
workspace.form.specification.values.intent.media = 'video';
|
||||
workspace.form.specification.values.video.first_frame_asset_id = 'asset-reference';
|
||||
workspace.form.specification.values.references[0].role = 'first_frame';
|
||||
renderCard(workspace, [
|
||||
{ code: 'video_duration_required', message: 'required', severity: 'blocker', path: 'video.total_duration_seconds' },
|
||||
{ code: 'video_shots_required', message: 'required', severity: 'blocker', path: 'video.shots' },
|
||||
]);
|
||||
expect(screen.getByRole('combobox', { name: '时长' })).toHaveValue('');
|
||||
expect(screen.getByRole('button', { name: '准备制作方案' })).toBeDisabled();
|
||||
expect(screen.queryByRole('button', { name: '增加时长' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('至少写一个视频画面。')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('allows AI preparation without requiring the user to write internal video shots', async () => {
|
||||
const workspace = referenceWorkspace();
|
||||
workspace.form.specification.values.intent.media = 'video';
|
||||
workspace.form.specification.values.video.first_frame_asset_id = 'asset-reference';
|
||||
workspace.form.specification.values.references[0].role = 'first_frame';
|
||||
workspace.form.specification.values.video.total_duration_seconds = 6;
|
||||
const actions = renderCard(workspace, [
|
||||
{ code: 'video_shots_required', message: 'required', severity: 'blocker', path: 'video.shots' },
|
||||
]);
|
||||
expect(screen.getByText('6 秒')).toBeInTheDocument();
|
||||
expect(screen.queryByText('至少写一个视频画面。')).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '准备制作方案' })).toBeEnabled();
|
||||
fireEvent.click(screen.getByRole('button', { name: '准备制作方案' }));
|
||||
await waitFor(() => expect(actions.requestQuote).toHaveBeenCalledOnce());
|
||||
});
|
||||
|
||||
it('restores the saved duration after a failed parameter edit', async () => {
|
||||
const workspace = referenceWorkspace();
|
||||
workspace.form.specification.values.intent.media = 'video';
|
||||
workspace.form.specification.values.video.total_duration_seconds = 6;
|
||||
const actions = renderCard(workspace);
|
||||
actions.applyFieldOperations.mockRejectedValueOnce(new Error('save failed'));
|
||||
fireEvent.click(screen.getByRole('button', { name: '增加时长' }));
|
||||
await waitFor(() => expect(screen.getByText('方案需要重试')).toBeInTheDocument());
|
||||
expect(screen.getByText('6 秒')).toBeInTheDocument();
|
||||
expect(screen.queryByText('7 秒')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('persists the displayed supported duration when entering video mode', async () => {
|
||||
const actions = renderCard();
|
||||
fireEvent.change(screen.getByRole('combobox', { name: '类型' }), { target: { value: 'video' } });
|
||||
|
||||
Reference in New Issue
Block a user