import { fireEvent, render, screen } from '@testing-library/react'; import { DEFAULT_PHYSICAL_MAP_CONFIG } from './types'; import { PhysicalMapPanel } from './PhysicalMapPanel'; const common = { maps: [], rootBodies: ['robot'], loading: false, nativeUrdf: false, showVisualMap: true, showMapCollision: false, editorDocument: null, onEditorPreview: () => {}, onEditorDraftChange: () => {}, onEditorApply: async () => true, onEditorExport: () => {}, onEditorConvert: async () => true, onEditorBindInteraction: () => {}, onEditorSelect: () => {}, onEditorSessionStateChange: () => {}, onMapDisplay: () => {}, onDraft: () => {}, }; describe('PhysicalMapPanel', () => { it('无选中实例时显示引导空态', () => { render( {}} />); expect(screen.getByText('未选择地图实例')).toBeInTheDocument(); expect(screen.getByLabelText('地图来源')).toHaveValue('none'); }); it('已有场景草稿时无需再次改参数也可一次编译', () => { const onApply = vi.fn(); render( , ); expect(screen.getByText(/场景草稿正在轻量预览/)).toBeInTheDocument(); const apply = screen.getByRole('button', { name: '应用并重新编译' }); expect(apply).toBeEnabled(); fireEvent.click(apply); expect(onApply).toHaveBeenCalledTimes(1); }); it('选择楼梯参数后请求重新编译', () => { const onApply = vi.fn(); render( , ); fireEvent.change(screen.getByLabelText('物理地图预设'), { target: { value: 'stairs' } }); fireEvent.change(screen.getByLabelText('台阶数量'), { target: { value: '6' } }); fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' })); expect(onApply).toHaveBeenCalledWith({ kind: 'builtin', config: expect.objectContaining({ preset: 'stairs', stairCount: 6 }), }); }); it('在右侧参数面板调整系统地形并提交', () => { const onApply = vi.fn(); render( , ); fireEvent.change(screen.getByLabelText('物理地图预设'), { target: { value: 'rough' } }); fireEvent.change(screen.getByLabelText('地形难度(0–1)'), { target: { value: '0.8' } }); fireEvent.change(screen.getByLabelText('随机种子'), { target: { value: '9' } }); fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' })); expect(onApply).toHaveBeenCalledWith({ kind: 'builtin', config: expect.objectContaining({ preset: 'rough', terrainDifficulty: 0.8, seed: 9, }), }); }); it('参数地形属性不再承载视口变换工具', () => { render( {}} />, ); expect(screen.queryByLabelText('地图变换模式')).not.toBeInTheDocument(); expect(screen.getByText(/已统一到视口浮动工具条/)).toBeInTheDocument(); }); it('表单参数与外部视口变换合并到同一份草稿', () => { const onDraft = vi.fn(); const onApply = vi.fn(); const initial = { kind: 'builtin' as const, config: { ...DEFAULT_PHYSICAL_MAP_CONFIG, preset: 'rough' as const }, }; const view = render( , ); fireEvent.change(screen.getByLabelText('地形边长(m)'), { target: { value: '7' } }); const staged = onDraft.mock.calls.at(-1)?.[0]; expect(staged).toMatchObject({ kind: 'builtin', config: { size: 7 } }); const moved = { ...staged, config: { ...staged.config, positionX: 2.4, positionY: -1.2 }, }; view.rerender( , ); expect(screen.getByLabelText('地形边长(m)')).toHaveValue(7); expect(screen.getByLabelText('位置 X(m)')).toHaveValue(2.4); fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' })); expect(onApply).toHaveBeenLastCalledWith( expect.objectContaining({ kind: 'builtin', config: expect.objectContaining({ size: 7, positionX: 2.4, positionY: -1.2 }), }), ); }); it('可以移动并旋转资产地图', () => { const onApply = vi.fn(); render( , ); fireEvent.change(screen.getByLabelText('位置 X(m)'), { target: { value: '2.5' } }); fireEvent.change(screen.getByLabelText('位置 Y(m)'), { target: { value: '-1.5' } }); fireEvent.change(screen.getByLabelText('旋转 Z(°)'), { target: { value: '45' } }); fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' })); expect(onApply).toHaveBeenCalledWith({ kind: 'builtin', config: expect.objectContaining({ positionX: 2.5, positionY: -1.5, yawDeg: 45 }), }); }); it('显示工程地图、实例变换、出生点和根 Body', () => { const onApply = vi.fn(); const onDraft = vi.fn(); render( , ); fireEvent.change(screen.getByLabelText('位置 X(m)'), { target: { value: '2.5' } }); fireEvent.change(screen.getByLabelText('位置 Y(m)'), { target: { value: '-1.5' } }); fireEvent.change(screen.getByLabelText('旋转 Z(°)'), { target: { value: '45' } }); fireEvent.change(screen.getByLabelText('地图出生点'), { target: { value: 'door' } }); expect(screen.getByLabelText('地图出生点')).toHaveValue('door'); fireEvent.change(screen.getByLabelText('机器人根 Body'), { target: { value: 'robot' } }); fireEvent.click(screen.getByRole('button', { name: '应用并重新编译' })); expect(onApply).toHaveBeenCalledWith( expect.objectContaining({ kind: 'project', descriptorPath: 'maps/warehouse/map.json', positionX: 2.5, positionY: -1.5, yawDeg: 45, spawnPointId: 'door', robotRootBody: 'robot', }), ); expect(onDraft).toHaveBeenLastCalledWith( expect.objectContaining({ kind: 'project', robotRootBody: 'robot' }), ); }); it('原生 URDF 模式只允许移除地图', () => { render( {}} />, ); expect(screen.getByRole('status')).toHaveTextContent('原生 URDF'); expect(screen.getByRole('button', { name: '应用并重新编译' })).toBeDisabled(); expect(screen.getByLabelText('地图来源')).not.toBeDisabled(); }); });