feat(web-platform): release V0.8.3 常规界面优化
This commit is contained in:
@@ -16,131 +16,20 @@ const renderLibrary = (
|
||||
);
|
||||
|
||||
describe('MapAssetLibrary', () => {
|
||||
it('把全部来源呈现在同一个放置与应用工作流中', () => {
|
||||
it('只负责地图包、物理原语和预设地形的放置入口', () => {
|
||||
expect(decodeMapLibraryDragPayload('not-json')).toBeNull();
|
||||
expect(decodeMapLibraryDragPayload('{"kind":"terrain","preset":"unknown"}')).toBeNull();
|
||||
renderLibrary();
|
||||
expect(screen.getByLabelText('地图资产库')).toHaveTextContent('统一地图资产库');
|
||||
expect(screen.getByLabelText('地图资产库')).toHaveTextContent('放置 → 预览 → 一次应用');
|
||||
const library = screen.getByLabelText('地图资产库');
|
||||
expect(library).toHaveTextContent('场景资产库');
|
||||
expect(library).toHaveTextContent('物理几何原语');
|
||||
expect(library).toHaveTextContent('预设地形');
|
||||
expect(library).not.toHaveTextContent('已放置地图');
|
||||
});
|
||||
|
||||
it('显示已放置地图树并支持选择、删除和重复添加工程地图源', () => {
|
||||
const onSelectMap = vi.fn();
|
||||
const onRemoveMap = vi.fn();
|
||||
const onAddProjectMap = vi.fn();
|
||||
render(
|
||||
<MapAssetLibrary
|
||||
disabled={false}
|
||||
terrainSize={8}
|
||||
maps={[
|
||||
{
|
||||
descriptorPath: 'maps/warehouse/map.json',
|
||||
schemaVersion: 1,
|
||||
id: 'warehouse',
|
||||
name: '仓库',
|
||||
spawnPoints: [],
|
||||
},
|
||||
]}
|
||||
placedMaps={[
|
||||
{
|
||||
id: 'map-a',
|
||||
name: '仓库',
|
||||
selection: { kind: 'project', descriptorPath: 'maps/warehouse/map.json' },
|
||||
},
|
||||
{
|
||||
id: 'map-b',
|
||||
name: '粗糙地形',
|
||||
selection: {
|
||||
kind: 'builtin',
|
||||
config: {
|
||||
preset: 'rough',
|
||||
size: 8,
|
||||
friction: 1,
|
||||
positionX: 0,
|
||||
positionY: 0,
|
||||
yawDeg: 0,
|
||||
slopeAngle: 12,
|
||||
stairCount: 8,
|
||||
obstacleCount: 10,
|
||||
seed: 1,
|
||||
terrainDifficulty: 0.5,
|
||||
terrainHorizontalScale: 0.12,
|
||||
terrainVerticalScale: 0.01,
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
activeMapId="map-a"
|
||||
onAdd={() => {}}
|
||||
onAddProjectMap={onAddProjectMap}
|
||||
onSelectTerrain={() => {}}
|
||||
onSelectMap={onSelectMap}
|
||||
onRemoveMap={onRemoveMap}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByLabelText('场景资产树')).toHaveTextContent('2 个实例');
|
||||
fireEvent.click(screen.getByRole('button', { name: '选择地图实例 粗糙地形' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '删除地图实例 仓库' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '放置工程地图 仓库' }));
|
||||
expect(onSelectMap).toHaveBeenCalledWith('map-b');
|
||||
expect(onRemoveMap).toHaveBeenCalledWith('map-a');
|
||||
expect(onAddProjectMap).toHaveBeenCalledWith('maps/warehouse/map.json');
|
||||
});
|
||||
|
||||
it('场景树为所有地图实例展示认证对象并可跨实例直接选择', () => {
|
||||
const onSelectObject = vi.fn();
|
||||
const editable = {
|
||||
schemaVersion: 1 as const,
|
||||
mapId: 'warehouse',
|
||||
revision: 0,
|
||||
objects: [
|
||||
{
|
||||
id: 'box-1',
|
||||
name: '共享方盒',
|
||||
type: 'box' as const,
|
||||
pose: {
|
||||
position: [0, 0, 0.5] as [number, number, number],
|
||||
quaternion: [1, 0, 0, 0] as [number, number, number, number],
|
||||
},
|
||||
parameters: { sizeX: 1, sizeY: 1, sizeZ: 1 },
|
||||
friction: [1, 0.005, 0.0001] as [number, number, number],
|
||||
rgba: [0.5, 0.6, 0.7, 1] as [number, number, number, number],
|
||||
placementMode: 'auto_ground' as const,
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
spawnPoints: [],
|
||||
};
|
||||
render(
|
||||
<MapAssetLibrary
|
||||
disabled={false}
|
||||
terrainSize={8}
|
||||
documents={new Map([['maps/warehouse/map.json', editable]])}
|
||||
placedMaps={[
|
||||
{
|
||||
id: 'map-a',
|
||||
name: '仓库 A',
|
||||
selection: { kind: 'project', descriptorPath: 'maps/warehouse/map.json' },
|
||||
},
|
||||
{
|
||||
id: 'map-b',
|
||||
name: '仓库 B',
|
||||
selection: { kind: 'project', descriptorPath: 'maps/warehouse/map.json' },
|
||||
},
|
||||
]}
|
||||
activeMapId="map-a"
|
||||
onAdd={() => {}}
|
||||
onSelectTerrain={() => {}}
|
||||
onSelectObject={onSelectObject}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByLabelText('场景资产树')).toHaveTextContent('2 个实例 · 2 个对象');
|
||||
fireEvent.click(screen.getAllByRole('button', { name: /共享方盒/ })[1]);
|
||||
expect(onSelectObject).toHaveBeenCalledWith('map-b', 'box-1');
|
||||
});
|
||||
|
||||
it('工程地图源使用与资产卡片一致的拖放入口', () => {
|
||||
it('地图包使用与资产卡片一致的添加和拖放入口', () => {
|
||||
const values = new Map<string, string>();
|
||||
const onAddProjectMap = vi.fn();
|
||||
const dataTransfer = {
|
||||
effectAllowed: 'none',
|
||||
setData: (type: string, value: string) => values.set(type, value),
|
||||
@@ -159,20 +48,21 @@ describe('MapAssetLibrary', () => {
|
||||
},
|
||||
]}
|
||||
onAdd={() => {}}
|
||||
onAddProjectMap={onAddProjectMap}
|
||||
onSelectTerrain={() => {}}
|
||||
/>,
|
||||
);
|
||||
const source = document.querySelector('[data-project-map="maps/warehouse/map.json"]')!;
|
||||
expect(source).toHaveAttribute('draggable', 'true');
|
||||
fireEvent.dragStart(source, { dataTransfer });
|
||||
fireEvent.click(screen.getByRole('button', { name: '放置工程地图 仓库' }));
|
||||
expect(decodeMapLibraryDragPayload(values.get(MAP_LIBRARY_DRAG_MIME) ?? '')).toEqual({
|
||||
kind: 'project',
|
||||
descriptorPath: 'maps/warehouse/map.json',
|
||||
});
|
||||
expect(values.get('text/plain')).toBe('仓库');
|
||||
expect(onAddProjectMap).toHaveBeenCalledWith('maps/warehouse/map.json');
|
||||
});
|
||||
|
||||
it('按所选放置方式添加认证资产', () => {
|
||||
it('按所选放置方式添加物理几何原语', () => {
|
||||
const onAdd = vi.fn();
|
||||
renderLibrary(onAdd);
|
||||
fireEvent.change(screen.getByLabelText('新增资产放置方式'), {
|
||||
@@ -182,7 +72,26 @@ describe('MapAssetLibrary', () => {
|
||||
expect(onAdd).toHaveBeenCalledWith('box', 'gravity');
|
||||
});
|
||||
|
||||
it('拖动资产时写入类型和放置方式', () => {
|
||||
it('可与视口工具条共享受控放置方式', () => {
|
||||
const onPlacementModeChange = vi.fn();
|
||||
render(
|
||||
<MapAssetLibrary
|
||||
disabled={false}
|
||||
terrainSize={8}
|
||||
placementMode="locked"
|
||||
onPlacementModeChange={onPlacementModeChange}
|
||||
onAdd={() => {}}
|
||||
onSelectTerrain={() => {}}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByLabelText('新增资产放置方式')).toHaveValue('locked');
|
||||
fireEvent.change(screen.getByLabelText('新增资产放置方式'), {
|
||||
target: { value: 'gravity' },
|
||||
});
|
||||
expect(onPlacementModeChange).toHaveBeenCalledWith('gravity');
|
||||
});
|
||||
|
||||
it('拖动物理原语时写入类型和放置方式', () => {
|
||||
const values = new Map<string, string>();
|
||||
const dataTransfer = {
|
||||
effectAllowed: 'none',
|
||||
@@ -200,76 +109,21 @@ describe('MapAssetLibrary', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('以示意图卡片选择系统参数化地形', () => {
|
||||
it('以示意图卡片添加或拖动预设地形', () => {
|
||||
const onSelectTerrain = vi.fn();
|
||||
renderLibrary(undefined, onSelectTerrain);
|
||||
expect(screen.getAllByText('8.00 × 8.00 m')).toHaveLength(9);
|
||||
fireEvent.click(screen.getByRole('button', { name: '添加随机粗糙地形' }));
|
||||
expect(onSelectTerrain).toHaveBeenCalledWith('rough');
|
||||
});
|
||||
|
||||
it('可把参数化地形拖到画布,并写入独立拖放类型', () => {
|
||||
const values = new Map<string, string>();
|
||||
const dataTransfer = {
|
||||
effectAllowed: 'none',
|
||||
setData: (type: string, value: string) => values.set(type, value),
|
||||
} as unknown as DataTransfer;
|
||||
renderLibrary();
|
||||
const terrain = document.querySelector('[data-system-terrain="rough"]')!;
|
||||
expect(terrain).toHaveAttribute('draggable', 'true');
|
||||
fireEvent.dragStart(terrain, { dataTransfer });
|
||||
renderLibrary(undefined, onSelectTerrain);
|
||||
expect(screen.getAllByText('8.00 × 8.00 m')).toHaveLength(9);
|
||||
fireEvent.click(screen.getByRole('button', { name: '添加随机粗糙地形' }));
|
||||
fireEvent.dragStart(document.querySelector('[data-system-terrain="wave"]')!, { dataTransfer });
|
||||
expect(onSelectTerrain).toHaveBeenCalledWith('rough');
|
||||
expect(decodeMapLibraryDragPayload(values.get(MAP_LIBRARY_DRAG_MIME) ?? '')).toEqual({
|
||||
kind: 'terrain',
|
||||
preset: 'rough',
|
||||
preset: 'wave',
|
||||
});
|
||||
expect(values.get('text/plain')).toBe('随机粗糙地形');
|
||||
});
|
||||
|
||||
it('集中显示认证资产与参数地形更改,并只触发一次场景编译', () => {
|
||||
const onApplyScene = vi.fn();
|
||||
const onDiscardScene = vi.fn();
|
||||
render(
|
||||
<MapAssetLibrary
|
||||
disabled={false}
|
||||
terrainSize={8}
|
||||
pendingSceneChangeCount={3}
|
||||
pendingSceneIds={['terrain-a']}
|
||||
placedMaps={[
|
||||
{
|
||||
id: 'terrain-a',
|
||||
name: '粗糙地形',
|
||||
selection: {
|
||||
kind: 'builtin',
|
||||
config: {
|
||||
preset: 'rough',
|
||||
size: 8,
|
||||
friction: 1,
|
||||
positionX: 0,
|
||||
positionY: 0,
|
||||
yawDeg: 0,
|
||||
slopeAngle: 12,
|
||||
stairCount: 8,
|
||||
obstacleCount: 10,
|
||||
seed: 1,
|
||||
terrainDifficulty: 0.5,
|
||||
terrainHorizontalScale: 0.12,
|
||||
terrainVerticalScale: 0.01,
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
onAdd={() => {}}
|
||||
onSelectTerrain={() => {}}
|
||||
onApplyScene={onApplyScene}
|
||||
onDiscardScene={onDiscardScene}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole('status')).toHaveTextContent('3 项场景更改待应用');
|
||||
expect(screen.getByRole('status')).toHaveTextContent('认证资产与参数地形共享同一草稿');
|
||||
expect(screen.getByLabelText('场景资产树')).toHaveTextContent('待应用');
|
||||
fireEvent.click(screen.getByRole('button', { name: '一次编译应用' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '放弃场景更改' }));
|
||||
expect(onApplyScene).toHaveBeenCalledTimes(1);
|
||||
expect(onDiscardScene).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user