1
This commit is contained in:
249
src/components/creative-agent/CreativeAgentWorkspace.test.tsx
Normal file
249
src/components/creative-agent/CreativeAgentWorkspace.test.tsx
Normal file
@@ -0,0 +1,249 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import type {
|
||||
CreativeAgentSessionSnapshot,
|
||||
CreativeAgentSseEvent,
|
||||
CreativeAgentStage,
|
||||
} from '../../../packages/shared/src/contracts/creativeAgent';
|
||||
import type { PuzzleCreativeTemplateProtocol } from '../../../packages/shared/src/contracts/puzzleCreativeTemplate';
|
||||
import { CreativeAgentStageTimeline } from './CreativeAgentStageTimeline';
|
||||
import { resolveCreativeAgentTargetSelectionStage } from './creativeAgentViewModel';
|
||||
import { CreativeAgentWorkspace } from './CreativeAgentWorkspace';
|
||||
|
||||
function createTemplate(
|
||||
overrides: Partial<PuzzleCreativeTemplateProtocol> = {},
|
||||
): PuzzleCreativeTemplateProtocol {
|
||||
return {
|
||||
templateId: 'puzzle.default-creative',
|
||||
title: '创意拼图',
|
||||
summary: '把图文灵感做成拼图。',
|
||||
previewImageSrc: null,
|
||||
supportedLevelMode: 'single_or_multi',
|
||||
minLevelCount: 1,
|
||||
maxLevelCount: 6,
|
||||
defaultLevelCount: 1,
|
||||
costRange: {
|
||||
minPoints: 2,
|
||||
maxPoints: 12,
|
||||
pricingUnit: 'point',
|
||||
reason: '按关卡数估算',
|
||||
},
|
||||
requiredDraftFields: ['workTitle'],
|
||||
imagePolicy: {
|
||||
allowUploadedImageDirectly: true,
|
||||
allowGeneratedImages: true,
|
||||
allowPerLevelReferenceImage: true,
|
||||
defaultCandidateCountPerLevel: 1,
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function createSession(
|
||||
overrides: Partial<CreativeAgentSessionSnapshot> = {},
|
||||
): CreativeAgentSessionSnapshot {
|
||||
return {
|
||||
sessionId: 'creative-session-1',
|
||||
stage: 'target_ready',
|
||||
inputSummary: {
|
||||
text: '做一个生日拼图',
|
||||
entryContext: 'creation_home',
|
||||
images: [],
|
||||
materialSummary: '做一个生日拼图',
|
||||
unsupportedCapabilities: [
|
||||
{
|
||||
playType: 'rpg',
|
||||
title: 'RPG',
|
||||
status: 'unsupported',
|
||||
reason: 'Phase 1 暂不开放',
|
||||
},
|
||||
],
|
||||
},
|
||||
messages: [
|
||||
{
|
||||
id: 'assistant-1',
|
||||
role: 'assistant',
|
||||
kind: 'chat',
|
||||
text: '拼图草稿已准备好。',
|
||||
createdAt: '2026-05-05T10:00:00.000Z',
|
||||
},
|
||||
],
|
||||
puzzleTemplateCatalog: [],
|
||||
puzzleTemplateSelection: null,
|
||||
puzzleImageGenerationPlan: null,
|
||||
targetBinding: {
|
||||
playType: 'puzzle',
|
||||
targetSessionId: 'puzzle-session-1',
|
||||
targetStage: 'puzzle-result',
|
||||
resultProfileId: 'puzzle-profile-1',
|
||||
},
|
||||
updatedAt: '2026-05-05T10:00:00.000Z',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
test('target ready session exposes the puzzle result entry action', () => {
|
||||
const onOpenTarget = vi.fn();
|
||||
const eventLog: CreativeAgentSseEvent[] = [
|
||||
{
|
||||
event: 'puzzle_cost_range',
|
||||
data: {
|
||||
sessionId: 'creative-session-1',
|
||||
costRange: {
|
||||
minPoints: 2,
|
||||
maxPoints: 12,
|
||||
pricingUnit: 'point',
|
||||
reason: '按关卡数估算',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
render(
|
||||
<CreativeAgentWorkspace
|
||||
session={createSession()}
|
||||
isBusy={false}
|
||||
isStreaming={false}
|
||||
error={null}
|
||||
eventLog={eventLog}
|
||||
onBack={() => {}}
|
||||
onSubmitMessage={() => {}}
|
||||
onConfirmTemplate={() => {}}
|
||||
onCancelTemplate={() => {}}
|
||||
onOpenTarget={onOpenTarget}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('拼图草稿已就绪')).toBeTruthy();
|
||||
expect(screen.getByText('可以进入结果页继续编辑')).toBeTruthy();
|
||||
expect(screen.getByText('预计 2-12 光点')).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开草稿' }));
|
||||
|
||||
expect(onOpenTarget).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('waiting confirmation shows template catalog before template config dialog', () => {
|
||||
const onConfirmTemplate = vi.fn();
|
||||
|
||||
render(
|
||||
<CreativeAgentWorkspace
|
||||
session={createSession({
|
||||
stage: 'waiting_template_confirmation',
|
||||
targetBinding: null,
|
||||
puzzleTemplateCatalog: [
|
||||
createTemplate(),
|
||||
createTemplate({
|
||||
templateId: 'puzzle.travel-memory',
|
||||
title: '旅行记忆拼图',
|
||||
summary: '把一次出行拆成地点、风景和故事节点拼图。',
|
||||
defaultLevelCount: 3,
|
||||
costRange: {
|
||||
minPoints: 4,
|
||||
maxPoints: 16,
|
||||
pricingUnit: 'point',
|
||||
reason: '按旅行节点估算',
|
||||
},
|
||||
}),
|
||||
],
|
||||
})}
|
||||
isBusy={false}
|
||||
isStreaming={false}
|
||||
error={null}
|
||||
eventLog={[]}
|
||||
onBack={() => {}}
|
||||
onSubmitMessage={() => {}}
|
||||
onConfirmTemplate={onConfirmTemplate}
|
||||
onOpenTarget={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole('button', { name: /创意拼图/u })).toBeTruthy();
|
||||
expect(screen.getByRole('button', { name: /旅行记忆拼图/u })).toBeTruthy();
|
||||
expect(screen.queryByRole('dialog', { name: '确认拼图模板' })).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /旅行记忆拼图/u }));
|
||||
|
||||
expect(screen.getByRole('dialog', { name: '确认拼图模板' })).toBeTruthy();
|
||||
expect(screen.getByText('预计 4 到 16 光点')).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /确认/u }));
|
||||
|
||||
expect(onConfirmTemplate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
templateId: 'puzzle.travel-memory',
|
||||
selectedLevelMode: 'multi_level',
|
||||
plannedLevelCount: 3,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('switching creative session clears pending template config dialog', () => {
|
||||
const firstSession = createSession({
|
||||
sessionId: 'creative-session-first',
|
||||
stage: 'waiting_template_confirmation',
|
||||
targetBinding: null,
|
||||
puzzleTemplateCatalog: [createTemplate()],
|
||||
});
|
||||
const secondSession = createSession({
|
||||
sessionId: 'creative-session-second',
|
||||
stage: 'waiting_template_confirmation',
|
||||
targetBinding: null,
|
||||
puzzleTemplateCatalog: [],
|
||||
});
|
||||
const { rerender } = render(
|
||||
<CreativeAgentWorkspace
|
||||
session={firstSession}
|
||||
isBusy={false}
|
||||
isStreaming={false}
|
||||
error={null}
|
||||
eventLog={[]}
|
||||
onBack={() => {}}
|
||||
onSubmitMessage={() => {}}
|
||||
onConfirmTemplate={() => {}}
|
||||
onOpenTarget={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /创意拼图/u }));
|
||||
|
||||
expect(screen.getByRole('dialog', { name: '确认拼图模板' })).toBeTruthy();
|
||||
|
||||
rerender(
|
||||
<CreativeAgentWorkspace
|
||||
session={secondSession}
|
||||
isBusy={false}
|
||||
isStreaming={false}
|
||||
error={null}
|
||||
eventLog={[]}
|
||||
onBack={() => {}}
|
||||
onSubmitMessage={() => {}}
|
||||
onConfirmTemplate={() => {}}
|
||||
onOpenTarget={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.queryByRole('dialog', { name: '确认拼图模板' })).toBeNull();
|
||||
});
|
||||
|
||||
test('target ready puzzle result binding resolves to puzzle-result stage', () => {
|
||||
expect(resolveCreativeAgentTargetSelectionStage('puzzle-result')).toBe(
|
||||
'puzzle-result',
|
||||
);
|
||||
expect(
|
||||
resolveCreativeAgentTargetSelectionStage('puzzle-agent-workspace'),
|
||||
).toBe('puzzle-agent-workspace');
|
||||
});
|
||||
|
||||
test('target ready timeline renders completed labels instead of active labels', () => {
|
||||
render(<CreativeAgentStageTimeline stage={'target_ready' as CreativeAgentStage} />);
|
||||
|
||||
expect(screen.getByText('素材已理解')).toBeTruthy();
|
||||
expect(screen.getByText('构思已完成')).toBeTruthy();
|
||||
expect(screen.getByText('草稿已生成')).toBeTruthy();
|
||||
expect(screen.queryByText('正在理解素材')).toBeNull();
|
||||
expect(screen.queryByText('正在构思')).toBeNull();
|
||||
});
|
||||
Reference in New Issue
Block a user