121 lines
3.8 KiB
TypeScript
121 lines
3.8 KiB
TypeScript
import { fireEvent, render, screen } from '@testing-library/react';
|
|
import type { EditableMapDocument } from '../../map/editor/types';
|
|
import type { SimulationSnapshot } from '../../simulation/SimulationSession';
|
|
import { SceneOutliner, countSceneSearchResults } from './SceneOutliner';
|
|
|
|
const snapshot = {
|
|
bodies: [
|
|
{ id: 0, name: 'world', parentId: 0 },
|
|
{ id: 1, name: 'base', parentId: 0 },
|
|
{ id: 2, name: 'arm', parentId: 1 },
|
|
],
|
|
joints: [
|
|
{
|
|
id: 7,
|
|
name: 'arm_joint',
|
|
bodyId: 2,
|
|
type: 3,
|
|
value: 0,
|
|
min: -1,
|
|
max: 1,
|
|
limitMin: -1,
|
|
limitMax: 1,
|
|
limited: true,
|
|
limitsIgnored: false,
|
|
editable: true,
|
|
axis: [0, 0, 1],
|
|
},
|
|
],
|
|
model: { nbody: 3 },
|
|
} as SimulationSnapshot;
|
|
|
|
const document: EditableMapDocument = {
|
|
schemaVersion: 1,
|
|
mapId: 'warehouse',
|
|
revision: 0,
|
|
objects: [
|
|
{
|
|
id: 'crate-1',
|
|
name: '木箱',
|
|
type: 'box',
|
|
pose: { position: [0, 0, 0.5], quaternion: [1, 0, 0, 0] },
|
|
parameters: { sizeX: 1, sizeY: 1, sizeZ: 1 },
|
|
friction: [1, 0.005, 0.0001],
|
|
rgba: [0.5, 0.6, 0.7, 1],
|
|
placementMode: 'auto_ground',
|
|
enabled: true,
|
|
},
|
|
],
|
|
spawnPoints: [],
|
|
};
|
|
|
|
const maps = [
|
|
{
|
|
id: 'map-a',
|
|
name: '仓库',
|
|
selection: { kind: 'project' as const, descriptorPath: 'maps/warehouse/map.json' },
|
|
},
|
|
];
|
|
const documents = new Map([['maps/warehouse/map.json', document]]);
|
|
|
|
function renderOutliner(overrides: Record<string, unknown> = {}) {
|
|
const props = {
|
|
snapshot,
|
|
maps,
|
|
documents,
|
|
selection: null,
|
|
query: '',
|
|
loading: false,
|
|
pendingSceneChangeCount: 0,
|
|
pendingSceneIds: [],
|
|
onSelectBody: vi.fn(),
|
|
onSelectJoint: vi.fn(),
|
|
onJointHover: vi.fn(),
|
|
onSelectMap: vi.fn(),
|
|
onSelectMapObject: vi.fn(),
|
|
onRemoveMap: vi.fn(),
|
|
onApplyScene: vi.fn(),
|
|
onDiscardScene: vi.fn(),
|
|
...overrides,
|
|
};
|
|
render(<SceneOutliner {...props} />);
|
|
return props;
|
|
}
|
|
|
|
describe('SceneOutliner', () => {
|
|
it('在一棵场景大纲中统一展示机器人、地图实例和地图物体', () => {
|
|
renderOutliner();
|
|
expect(screen.getByLabelText('场景资产树')).toHaveTextContent('机器人');
|
|
expect(screen.getByLabelText('场景资产树')).toHaveTextContent('地图与环境');
|
|
expect(screen.getByRole('treeitem', { name: /arm_joint/ })).toBeVisible();
|
|
expect(screen.getByRole('treeitem', { name: /木箱/ })).toBeVisible();
|
|
expect(countSceneSearchResults(snapshot, maps, documents, '木箱')).toBe(2);
|
|
});
|
|
|
|
it('把所有选择统一上报为稳定 id', () => {
|
|
const props = renderOutliner();
|
|
fireEvent.click(screen.getByRole('treeitem', { name: 'base' }));
|
|
fireEvent.click(screen.getByRole('treeitem', { name: /arm_joint/ }));
|
|
fireEvent.click(screen.getByRole('treeitem', { name: /^仓库/ }));
|
|
fireEvent.click(screen.getByRole('treeitem', { name: /木箱/ }));
|
|
expect(props.onSelectBody).toHaveBeenCalledWith(1);
|
|
expect(props.onSelectJoint).toHaveBeenCalledWith(7, 2);
|
|
expect(props.onSelectMap).toHaveBeenCalledWith('map-a');
|
|
expect(props.onSelectMapObject).toHaveBeenCalledWith('map-a', 'crate-1');
|
|
});
|
|
|
|
it('在大纲中集中处理场景草稿与实例删除', () => {
|
|
const props = renderOutliner({
|
|
pendingSceneChangeCount: 2,
|
|
pendingSceneIds: ['map-a'],
|
|
});
|
|
expect(screen.getByRole('status')).toHaveTextContent('2 项场景更改待应用');
|
|
fireEvent.click(screen.getByRole('button', { name: '应用场景' }));
|
|
fireEvent.click(screen.getByRole('button', { name: '放弃更改' }));
|
|
fireEvent.click(screen.getByRole('button', { name: '删除地图实例 仓库' }));
|
|
expect(props.onApplyScene).toHaveBeenCalledOnce();
|
|
expect(props.onDiscardScene).toHaveBeenCalledOnce();
|
|
expect(props.onRemoveMap).toHaveBeenCalledWith('map-a');
|
|
});
|
|
});
|