Files
Genarrative/src/components/CustomWorldGenerationView.test.tsx

278 lines
9.9 KiB
TypeScript

/* @vitest-environment jsdom */
import { render, screen } from '@testing-library/react';
import { describe, expect, test } from 'vitest';
import type { CustomWorldGenerationProgress } from '../../packages/shared/src/contracts/runtime';
import { CustomWorldGenerationView } from './CustomWorldGenerationView';
function createProgress(
overrides: Partial<CustomWorldGenerationProgress> = {},
): CustomWorldGenerationProgress {
return {
phaseId: 'draft_foundation',
phaseLabel: '整理草稿',
phaseDetail: '正在整理当前生成步骤。',
batchLabel: '第 2 批',
overallProgress: 42,
completedWeight: 21,
totalWeight: 50,
elapsedMs: 125_000,
estimatedRemainingMs: 75_000,
activeStepIndex: 1,
steps: [
{
id: 'step-1',
label: '收集设定',
detail: '整理初始输入。',
completed: 1,
total: 1,
status: 'completed',
},
{
id: 'step-2',
label: '编译草稿',
detail: '生成首版结构。',
completed: 2,
total: 4,
status: 'active',
},
{
id: 'step-3',
label: '写回结果',
detail: '同步结果页。',
completed: 0,
total: 4,
status: 'pending',
},
],
...overrides,
};
}
describe('CustomWorldGenerationView', () => {
test.each(['拼图草稿生成进度', '抓大鹅草稿生成进度'])(
'renders the circular hero and only the current step summary for %s',
(progressTitle) => {
const { container } = render(
<CustomWorldGenerationView
settingText="竖屏生成题材"
progress={createProgress()}
isGenerating
error={null}
onBack={() => {}}
onEditSetting={() => {}}
onRetry={() => {}}
backLabel="返回创作中心"
settingDescription={null}
settingActionLabel={null}
progressTitle={progressTitle}
/>,
);
expect(container.firstChild).toBeTruthy();
expect((container.firstChild as HTMLElement).className).toContain(
'z-[1]',
);
const pageVideo = screen.getByTestId(
'generation-page-background-video',
) as HTMLVideoElement;
expect(pageVideo.parentElement?.className).toContain('z-0');
expect(pageVideo.parentElement?.className).toContain('bg-transparent');
expect(pageVideo.parentElement?.className).not.toContain('bg-[#fff4ea]');
expect((container.firstChild as HTMLElement).contains(pageVideo)).toBe(
true,
);
expect(pageVideo.autoplay).toBe(true);
expect(pageVideo.loop).toBe(true);
expect(pageVideo.muted).toBe(true);
expect(pageVideo.playsInline).toBe(true);
expect(pageVideo.getAttribute('preload')).toBe('auto');
expect(
document.querySelector(
'video[data-testid="generation-page-background-video"] source[type="video/mp4"]',
),
).toBeTruthy();
expect(
screen.getByRole('button', { name: '返回创作中心' }),
).toBeTruthy();
expect(
screen.getByRole('button', { name: '返回创作中心' }).className,
).toContain('text-xs');
expect(screen.getByText('世界建设中')).toBeTruthy();
expect(screen.getByText('世界建设中').className).toContain('text-xs');
expect(screen.getByTestId('generation-hero-wait-card').className).toContain(
'text-center',
);
expect(screen.getByTestId('generation-hero-elapsed-card').className).toContain(
'text-center',
);
expect(screen.getByTestId('generation-hero-wait-card').className).toContain(
'bg-white/58',
);
expect(screen.getByTestId('generation-hero-elapsed-card').className).toContain(
'bg-white/58',
);
expect(screen.getByText('预计等待').className).toContain('text-[9px]');
expect(screen.getByText('已耗时').className).toContain('text-[9px]');
expect(screen.getByText('预计等待').parentElement?.className).toContain(
'justify-center',
);
expect(screen.getByText('已耗时').parentElement?.className).toContain(
'justify-center',
);
expect(screen.getByText('1 分 15 秒')).toBeTruthy();
expect(screen.getByText('2 分 5 秒')).toBeTruthy();
expect(screen.queryByText('预计还需 1 分 15 秒')).toBeNull();
expect(screen.queryByText('已耗时 2 分 5 秒')).toBeNull();
expect(screen.queryByText('计时')).toBeNull();
expect(screen.getByTestId('generation-hero-progress-content').className).toContain(
'justify-start',
);
expect(screen.getByTestId('generation-hero-progress-content').className).toContain(
'z-30',
);
expect(screen.getByTestId('generation-hero-progress-content').className).toContain(
'pt-[2%]',
);
expect(screen.getByText('总进度').className).toContain('text-[9px]');
expect(screen.getByText('42%').className).toContain('text-[1.15rem]');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.className,
).toContain('w-[min(400px,calc(100%_-_0.75rem))]');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.className,
).toContain('max-w-full');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.className,
).toContain('aspect-square');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.getAttribute('data-ring-start-degrees'),
).toBe('135');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.getAttribute('data-ring-fill-start-degrees'),
).toBe('135');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.getAttribute('data-ring-sweep-degrees'),
).toBe('270');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.getAttribute('data-ring-gap-degrees'),
).toBe('90');
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.getAttribute('data-ring-fill-degrees'),
).toBe('113');
expect(screen.getByTestId('generation-hero-progress-ring').tagName).toBe(
'svg',
);
expect(screen.getByTestId('generation-hero-progress-ring').getAttribute('class')).toContain(
'z-0',
);
expect(
screen
.getByTestId('generation-hero-progress-ring')
.getAttribute('viewBox'),
).toBe('0 0 400 400');
expect(
screen
.getByTestId('generation-hero-progress-ring-track')
.getAttribute('r'),
).toBe('166');
expect(
screen
.getByTestId('generation-hero-progress-ring-track')
.getAttribute('stroke-width'),
).toBe('18');
expect(
screen
.getByTestId('generation-hero-progress-ring-track')
.getAttribute('transform'),
).toBe('rotate(135 200 200)');
expect(
screen
.getByTestId('generation-hero-progress-ring-fill')
.getAttribute('transform'),
).toBe('rotate(135 200 200)');
expect(
screen
.getByTestId('generation-hero-progress-ring-fill')
.getAttribute('stroke-dasharray'),
).toMatch(/^328\.\d{2} 1043\.\d{2}$/u);
expect(
screen.getByRole('progressbar', { name: progressTitle }),
).toBeTruthy();
expect(
screen
.getByRole('progressbar', { name: progressTitle })
.getAttribute('aria-valuenow'),
).toBe('42');
expect(screen.getByText('当前步骤')).toBeTruthy();
expect(screen.getByText('当前步骤').className).toContain('text-[10px]');
expect(screen.getByText('编译草稿')).toBeTruthy();
expect(screen.getByText('编译草稿').className).toContain('text-[14px]');
expect(screen.getByText('进行中 50%')).toBeTruthy();
expect(screen.getByText('进行中 50%').className).toContain('text-[11px]');
expect(
screen.getByTestId('generation-current-step-card').className,
).toContain('bg-white/58');
expect(
screen.getByRole('progressbar', { name: '编译草稿 进度' }),
).toBeTruthy();
expect(screen.queryByText('收集设定')).toBeNull();
expect(screen.queryByText('写回结果')).toBeNull();
expect(screen.queryByText('当前批次')).toBeNull();
expect(screen.queryByText('正在整理当前设定步骤')).toBeNull();
},
);
test('keeps the setting information panel as compact information cards', () => {
render(
<CustomWorldGenerationView
settingText="大鱼吃小鱼题材"
anchorEntries={[
{ id: 'topic', label: '题材', value: '火锅' },
{ id: 'count', label: '素材数量', value: '20 种素材' },
]}
progress={createProgress()}
isGenerating
error={null}
onBack={() => {}}
onEditSetting={() => {}}
onRetry={() => {}}
backLabel="返回创作中心"
settingDescription={null}
settingActionLabel={null}
settingTitle="当前大鱼吃小鱼信息"
progressTitle="大鱼吃小鱼草稿生成进度"
/>,
);
expect(screen.getByText('当前大鱼吃小鱼信息')).toBeTruthy();
expect(screen.getByText('当前大鱼吃小鱼信息').className).toContain('text-[13px]');
expect(screen.getByText('题材')).toBeTruthy();
expect(screen.getByText('题材').className).toContain('text-[9px]');
expect(screen.getByText('火锅')).toBeTruthy();
expect(screen.getByText('火锅').className).toContain('text-[13px]');
expect(screen.getByText('素材数量')).toBeTruthy();
expect(screen.getByText('20 种素材')).toBeTruthy();
expect(screen.queryByText('大鱼吃小鱼题材')).toBeNull();
expect(screen.getByTestId('generation-page-background-video')).toBeTruthy();
});
});