/* @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 { 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( {}} 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( {}} 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(); }); });