import { describe, expect, it, vi } from 'vitest' import type { SgsSdkApiProvider } from '@/data/providers/sgsSdkApiProvider' import { SdkGuideRouteRepository } from '@/repositories/SdkGuideRouteRepository' const floorId = '2065808921272119298' const createProvider = () => { const planRoute = vi.fn().mockResolvedValue({ distance: 24, segments: [{ floorId, floorName: '1.0层', transferType: 'WALK', pathPoints: [ { x: 2, y: 0, z: 3 }, { x: 8, y: 0, z: 9 } ] }] }) return { getManifest: vi.fn().mockResolvedValue({ mapId: '1', capabilities: { routePlanning: true }, floors: [{ floorId, floorCode: 'L1', floorName: '1.0层' }] }), getMapDiagnostics: vi.fn().mockResolvedValue({ floors: [{ floorId, floorCode: 'L1', floorName: '1.0层', status: 'OK', routePlanningReady: true, navigablePlaceCount: 1 }] }), getNavigablePlaces: vi.fn().mockResolvedValue([{ id: 'route-node-service-desk', sourceId: 'poi-service-desk', anchorId: 'anchor-service-desk', name: '服务台 出入口', floorId, floorCode: 'L1', floorName: '1.0层', x: 2, y: 0, z: 3, nodeId: 'start-node' }]), planRoute } as unknown as SgsSdkApiProvider } describe('SdkGuideRouteRepository', () => { it('使用 manifest 路线能力判断就绪,不调用全图 diagnostics 慢接口', async () => { const provider = createProvider() const repository = new SdkGuideRouteRepository(provider) const readiness = await repository.getRouteReadiness() expect(readiness.ready).toBe(true) expect(provider.getManifest).toHaveBeenCalledTimes(1) expect(provider.getMapDiagnostics).not.toHaveBeenCalled() }) it('允许未预绑定路网的地图对象作为终点,并向后端提交其定位坐标', async () => { const provider = createProvider() const repository = new SdkGuideRouteRepository(provider) const route = await repository.findRoute('anchor-service-desk', { poiId: 'space-stamp', name: '文创盖章打卡', floorId, floorLabel: '1F', categoryLabel: '购物空间', positionGltf: [61.8, 1.2, 45.3] }) expect(provider.planRoute).toHaveBeenCalledWith(expect.objectContaining({ startNodeId: 'start-node', endFloorId: floorId, endX: 61.8, endY: 45.3, endNodeId: null, verticalTransferPolicy: 'PREFER_ELEVATOR_ESCALATOR' })) expect(route.end.name).toBe('文创盖章打卡') expect(route.distanceMeters).toBe(24) }) it('保留业务对象 ID,使地图标签可精确回连到对应接入点', async () => { const repository = new SdkGuideRouteRepository(createProvider()) const targets = await repository.listRouteTargets() expect(targets).toEqual([expect.objectContaining({ routeTargetId: 'anchor-service-desk', poiId: 'route-node-service-desk', sourceId: 'poi-service-desk', routeNodeId: 'start-node' })]) }) it('路线起点选择只读取当前楼层目标,不扫描全馆楼层', async () => { const provider = createProvider() const repository = new SdkGuideRouteRepository(provider) const targets = await repository.listRouteTargetsForFloor(floorId) expect(targets).toHaveLength(1) expect(provider.getNavigablePlaces).toHaveBeenCalledTimes(1) expect(provider.getNavigablePlaces).toHaveBeenCalledWith(floorId) expect(provider.getMapDiagnostics).not.toHaveBeenCalled() }) it('为只有 nodeId 的路网节点生成稳定兜底身份', async () => { const provider = createProvider() provider.getNavigablePlaces = vi.fn().mockResolvedValue([{ id: null, sourceId: 'space-42', name: '球幕影院节点', floorId, floorCode: 'L1', floorName: '1.0层', x: 1, y: 0, z: 2, nodeId: 'node-only' }]) const repository = new SdkGuideRouteRepository(provider) const targets = await repository.listRouteTargets() expect(targets).toEqual([expect.objectContaining({ routeTargetId: 'node-node-only:node-only', poiId: 'node-node-only', sourceId: 'space-42', routeNodeId: 'node-only' })]) }) it('允许地图对象坐标作为起点,由路线服务负责吸附到正式路网', async () => { const provider = createProvider() const repository = new SdkGuideRouteRepository(provider) await repository.findRoute({ poiId: 'hall-unanchored', name: '球幕影院', floorId, floorLabel: '1F', positionGltf: [1.7, 3.3, -5.6] }, { poiId: 'space-stamp', name: '文创盖章打卡', floorId, floorLabel: '1F', positionGltf: [61.8, 1.2, 45.3] }) expect(provider.planRoute).toHaveBeenCalledWith(expect.objectContaining({ startX: 1.7, startY: -5.6, startNodeId: null, endNodeId: null })) }) it('将路线接口异常转换为不暴露内部请求细节的用户错误', async () => { const provider = createProvider() provider.planRoute = vi.fn().mockRejectedValue(new Error( 'SGS 数据接口请求失败: 500 /app-api/gis/sdk/routes/plan body="internal response"' )) const repository = new SdkGuideRouteRepository(provider) await expect(repository.findRoute({ poiId: 'start-poi', name: '起点', floorId, floorLabel: '1F', positionGltf: [1, 0, 2] }, { poiId: 'end-poi', name: '终点', floorId, floorLabel: '1F', positionGltf: [3, 0, 4] })).rejects.toMatchObject({ code: 'ROUTE_SERVICE_UNAVAILABLE', message: '路线服务暂时不可用,请稍后重试' }) }) })