/* @vitest-environment jsdom */ import { fireEvent, render, screen, within } from '@testing-library/react'; import { expect, test, vi } from 'vitest'; import type { Match3DAgentSessionSnapshot } from '../../../../packages/shared/src/contracts/match3dAgent'; import { Match3DCreationWorkspace } from './Match3DCreationWorkspace'; const baseSession: Match3DAgentSessionSnapshot = { sessionId: 'match3d-session-1', currentTurn: 0, progressPercent: 0, stage: 'collecting_config', anchorPack: { theme: { key: 'theme', label: '题材主题', value: '水果摊', status: 'confirmed', }, clearCount: { key: 'clearCount', label: '需要消除次数', value: '8', status: 'confirmed', }, difficulty: { key: 'difficulty', label: '难度', value: '3', status: 'confirmed', }, }, config: { themeText: '水果摊', referenceImageSrc: null, clearCount: 8, difficulty: 3, assetStyleId: 'cel-cartoon', assetStyleLabel: '赛璐璐卡通', assetStylePrompt: '明亮赛璐璐卡通 2D 游戏道具风格,清晰线稿,硬边阴影,饱和配色,轮廓醒目。', generateClickSound: false, }, draft: null, messages: [ { id: 'message-1', role: 'assistant', kind: 'chat', text: '旧会话固定追问不再作为主入口。', createdAt: '2026-05-10T10:00:00.000Z', }, ], lastAssistantReply: '旧会话固定追问不再作为主入口。', publishedProfileId: null, updatedAt: '2026-05-10T10:00:00.000Z', }; function confirmMatch3DPointCost() { const confirmDialog = screen.getByRole('dialog', { name: '确认消耗泥点', }); expect(within(confirmDialog).getByText('消耗 10 泥点')).toBeTruthy(); fireEvent.click(within(confirmDialog).getByRole('button', { name: '确定' })); } test('match3d workspace submits derived entry form payload instead of agent chat', () => { const onCreateFromForm = vi.fn(); const onExecuteAction = vi.fn(); render( {}} onExecuteAction={onExecuteAction} onCreateFromForm={onCreateFromForm} />, ); expect(screen.getByText('抓大鹅')).toBeTruthy(); expect(screen.getByLabelText('想做一个什么题材的抓大鹅?')).toBeTruthy(); expect(screen.queryByText('2D素材风格')).toBeNull(); expect(screen.queryByRole('button', { name: '扁平图标' })).toBeNull(); expect(screen.queryByRole('button', { name: '自定义' })).toBeNull(); expect(screen.getByText('消耗10泥点')).toBeTruthy(); expect(screen.queryByRole('button', { name: '生成音效' })).toBeNull(); expect(screen.queryByText('参考图')).toBeNull(); expect(screen.queryByLabelText('上传抓大鹅参考图')).toBeNull(); expect(screen.queryByLabelText('需要消除次数')).toBeNull(); expect(screen.queryByLabelText('难度数值')).toBeNull(); expect(screen.queryByText('物品')).toBeNull(); expect(screen.queryByText('旧会话固定追问不再作为主入口。')).toBeNull(); fireEvent.change(screen.getByLabelText('想做一个什么题材的抓大鹅?'), { target: { value: '赛博水果摊' }, }); fireEvent.click(screen.getByRole('button', { name: '进阶' })); fireEvent.click(screen.getByRole('button', { name: /生成抓大鹅草稿/u })); expect(onCreateFromForm).not.toHaveBeenCalled(); confirmMatch3DPointCost(); expect(onCreateFromForm).toHaveBeenCalledWith({ seedText: '赛博水果摊题材,消除16次,难度6', themeText: '赛博水果摊', referenceImageSrc: null, clearCount: 16, difficulty: 6, generateClickSound: false, }); expect(onExecuteAction).not.toHaveBeenCalled(); }); test('match3d workspace can defer visible chrome to the unified creation page', () => { const { container } = render( {}} onExecuteAction={() => {}} onCreateFromForm={() => {}} title={null} unifiedChrome />, ); const workspace = container.querySelector('.match3d-agent-workspace'); expect(workspace?.getAttribute('data-unified-chrome')).toBe('true'); expect(workspace?.className).toContain('max-w-none'); expect(workspace?.className).not.toContain('h-full'); expect(workspace?.className).not.toContain('overflow-hidden'); expect(workspace?.className).not.toContain('platform-remap-surface'); expect(screen.queryByRole('heading', { name: '抓大鹅' })).toBeNull(); const themeInput = screen.getByLabelText('想做一个什么题材的抓大鹅?'); expect(themeInput).toBeTruthy(); expect(themeInput.className).not.toContain('h-full'); }); test('match3d workspace omits legacy asset style fields from entry payload', () => { const onCreateFromForm = vi.fn(); render( {}} onExecuteAction={() => {}} onCreateFromForm={onCreateFromForm} />, ); fireEvent.change(screen.getByLabelText('想做一个什么题材的抓大鹅?'), { target: { value: '复古水果铺' }, }); fireEvent.click(screen.getByRole('button', { name: /生成抓大鹅草稿/u })); confirmMatch3DPointCost(); const payload = onCreateFromForm.mock.calls[0]?.[0] ?? {}; expect('assetStyleId' in payload).toBe(false); expect('assetStyleLabel' in payload).toBe(false); expect('assetStylePrompt' in payload).toBe(false); }); test('match3d workspace keeps click sound generation disabled from entry form', () => { const onCreateFromForm = vi.fn(); render( {}} onExecuteAction={() => {}} onCreateFromForm={onCreateFromForm} />, ); fireEvent.change(screen.getByLabelText('想做一个什么题材的抓大鹅?'), { target: { value: '海岛甜品' }, }); fireEvent.click(screen.getByRole('button', { name: /生成抓大鹅草稿/u })); confirmMatch3DPointCost(); expect(onCreateFromForm).toHaveBeenCalledWith( expect.objectContaining({ themeText: '海岛甜品', generateClickSound: false, }), ); }); test('match3d workspace falls back to compile action when restored from the legacy route', () => { const onExecuteAction = vi.fn(); render( {}} onExecuteAction={onExecuteAction} />, ); expect( (screen.getByLabelText('想做一个什么题材的抓大鹅?') as HTMLTextAreaElement) .value, ).toBe('水果摊'); expect( screen.getByRole('button', { name: '轻松' }).getAttribute('aria-pressed'), ).toBe('true'); expect(screen.queryByText('2D素材风格')).toBeNull(); expect(screen.queryByRole('button', { name: '赛璐璐卡通' })).toBeNull(); fireEvent.click(screen.getByRole('button', { name: /生成抓大鹅草稿/u })); confirmMatch3DPointCost(); expect(onExecuteAction).toHaveBeenCalledWith({ action: 'match3d_compile_draft', generateClickSound: false, }); });