Files
Genarrative/src/components/visual-novel-creation/VisualNovelAgentWorkspace.test.tsx
T
kdletters deea0e8655 扩展宿主调用链扫描
自动发现 H5 HostBridge 真实能力调用链

补齐 runtime 回读与 wrapper 消费者扫描兜底

区分壳源码和 H5 业务调用链的禁替身词表

将视觉小说生产预览数据从 mock 命名收口为本地预览命名

更新原生壳验收文档和共享决策记录
2026-06-19 02:45:56 +08:00

149 lines
5.5 KiB
TypeScript

/* @vitest-environment jsdom */
import { fireEvent, render, screen } from '@testing-library/react';
import type { ComponentProps } from 'react';
import { expect, test, vi } from 'vitest';
import { buildVisualNovelForbiddenCopyPattern } from '../visual-novel-runtime/visualNovelForbiddenCopy';
import { visualNovelLocalPreviewSession } from '../visual-novel-runtime/visualNovelLocalPreviewData';
import { VisualNovelAgentWorkspace } from './VisualNovelAgentWorkspace';
import {
buildVisualNovelEntryGenerationAnchorEntries,
buildVisualNovelEntryGenerationProgress,
} from './visualNovelEntryGeneration';
function renderWorkspace(
ui?: Partial<ComponentProps<typeof VisualNovelAgentWorkspace>>,
) {
return render(
<VisualNovelAgentWorkspace onBack={() => {}} session={null} {...ui} />,
);
}
test('visual novel workspace only exposes one-line input and visual style entry', () => {
const onCreateFromForm = vi.fn();
renderWorkspace({ onCreateFromForm, title: '视觉小说' });
expect(screen.getByText('BETA').className).toContain('rounded-full');
expect(screen.getByText('BETA').className).toContain(
'border-[var(--platform-warm-border)]',
);
expect(screen.getByLabelText('一句话创作')).toBeTruthy();
expect(screen.getByText('视觉画风')).toBeTruthy();
expect(screen.getByText('视觉画风').closest('div')?.className).toContain(
'platform-subpanel',
);
expect(screen.getByText('视觉画风').closest('div')?.className).toContain(
'bg-white/52',
);
expect(
screen
.getByRole('button', { name: '映画动画' })
.querySelector('img')
?.getAttribute('src'),
).toBe('/visual-novel-style-references/cinematic-anime.png');
expect(
screen
.getByRole('button', { name: '水彩绘本' })
.querySelector('img')
?.getAttribute('src'),
).toBe('/visual-novel-style-references/watercolor.png');
expect(
screen
.getByRole('button', { name: '像素霓虹' })
.querySelector('img')
?.getAttribute('src'),
).toBe('/visual-novel-style-references/pixel-noir.png');
expect(
screen
.getByRole('button', { name: '水墨幻想' })
.querySelector('img')
?.getAttribute('src'),
).toBe('/visual-novel-style-references/ink-fantasy.png');
expect(
screen
.getByRole('button', { name: '柔彩校园' })
.querySelector('img')
?.getAttribute('src'),
).toBe('/visual-novel-style-references/soft-pastel.png');
expect(
screen
.getByRole('button', { name: '暗色哥特' })
.querySelector('img')
?.getAttribute('src'),
).toBe('/visual-novel-style-references/dark-gothic.png');
expect(screen.getByText('消耗20泥点')).toBeTruthy();
expect(screen.queryByText(buildVisualNovelForbiddenCopyPattern())).toBeNull();
expect(screen.queryByRole('button', { name: '文档' })).toBeNull();
expect(screen.queryByRole('button', { name: '空白' })).toBeNull();
expect(screen.queryByLabelText('上传文档')).toBeNull();
expect(screen.queryByText('进入结果页')).toBeNull();
expect(screen.queryByText('Agent')).toBeNull();
});
test('visual novel workspace submits idea and selected visual style as seed text', () => {
const onCreateFromForm = vi.fn();
renderWorkspace({ onCreateFromForm });
fireEvent.change(screen.getByLabelText('一句话创作'), {
target: { value: '失忆画师在雨夜剧场寻找旧胶片。' },
});
fireEvent.click(screen.getByRole('button', { name: '像素霓虹' }));
fireEvent.click(screen.getByRole('button', { name: /生成视觉小说草稿/u }));
expect(onCreateFromForm).toHaveBeenCalledWith({
sourceMode: 'idea',
sourceAssetIds: [],
ideaText: '失忆画师在雨夜剧场寻找旧胶片。',
visualStyleId: 'pixel-noir',
visualStyleLabel: '像素霓虹',
visualStylePrompt:
'高可读像素视觉小说画风,霓虹反差、硬朗轮廓和复古界面气质。',
seedText:
'失忆画师在雨夜剧场寻找旧胶片。\n视觉画风:像素霓虹\n画风要求:高可读像素视觉小说画风,霓虹反差、硬朗轮廓和复古界面气质。',
});
});
test('visual novel workspace restores idea text from existing session', () => {
renderWorkspace({ session: visualNovelLocalPreviewSession });
expect(
(screen.getByLabelText('一句话创作') as HTMLTextAreaElement).value,
).toBe('想做一个雪夜列车和旧电台有关的悬疑视觉小说。');
});
test('visual novel generation helpers build process page data', () => {
const payload = {
sourceMode: 'idea' as const,
seedText: '雨夜书店\n视觉画风:水彩绘本\n画风要求:透明水彩与绘本质感。',
sourceAssetIds: [],
ideaText: '雨夜书店',
visualStyleId: 'watercolor' as const,
visualStyleLabel: '水彩绘本',
visualStylePrompt: '透明水彩与绘本质感。',
};
expect(buildVisualNovelEntryGenerationAnchorEntries(payload)).toEqual([
{ id: 'visual-novel-idea', label: '一句话', value: '雨夜书店' },
{ id: 'visual-novel-style', label: '视觉画风', value: '水彩绘本' },
{
id: 'visual-novel-target',
label: '生成目标',
value: '可编辑并可试玩的视觉小说草稿',
},
]);
const progress = buildVisualNovelEntryGenerationProgress(
1_000,
'generating',
8_000,
);
expect(progress.phaseId).toBe('visual-novel-world');
expect(progress.overallProgress).toBeGreaterThan(0);
expect(progress.phaseLabel).toBe('扩展世界观');
expect(progress.steps.some((step) => step.status === 'active')).toBe(true);
});