import { beforeEach, describe, expect, it, vi } from 'vitest' import { createSgsSdkApiProvider } from '@/data/providers/sgsSdkApiProvider' import { clearGuidePerformanceRecords, getGuidePerformanceSummary } from '@/services/performance/guidePerformance' describe('SgsSdkApiProvider mutable floor metadata cache', () => { const values = new Map() const localStorage = { getItem: (key: string) => values.get(key) || null, setItem: (key: string, value: string) => values.set(key, value), removeItem: (key: string) => values.delete(key), clear: () => values.clear() } beforeEach(() => { values.clear() clearGuidePerformanceRecords() vi.restoreAllMocks() vi.stubGlobal('window', { localStorage }) }) it('uses the persisted manifest cache after a provider reload', async () => { const request = vi.fn((options: { url: string success: (response: unknown) => void }) => { expect(options.url).toContain('/gis/sdk/maps/1/manifest') options.success({ statusCode: 200, header: { 'content-type': 'application/json' }, data: { code: 0, data: { mapId: '1', dataVersion: 'manifest-v1', floors: [{ floorId: 'floor-1', floorCode: 'L1', floorName: '1.0层' }] } } }) }) vi.stubGlobal('uni', { request }) await expect(createSgsSdkApiProvider().getManifest()).resolves.toMatchObject({ dataVersion: 'manifest-v1' }) clearGuidePerformanceRecords() const reloadedProvider = createSgsSdkApiProvider() await expect(reloadedProvider.getManifest()).resolves.toMatchObject({ dataVersion: 'manifest-v1' }) expect(request).toHaveBeenCalledTimes(1) expect(getGuidePerformanceSummary()).toMatchObject({ apiCacheHitCount: 1, apiNetworkRequestCount: 0 }) }) it('revalidates floor spaces after reload instead of returning a persisted old name', async () => { let spaceName = '红花路' const request = vi.fn((options: { success: (response: unknown) => void }) => { options.success({ statusCode: 200, header: { 'content-type': 'application/json' }, data: { code: 0, data: [{ id: 'road-space', name: spaceName, type: 'road_area', floorId: 'exterior' }] } }) }) vi.stubGlobal('uni', { request }) const firstProvider = createSgsSdkApiProvider() await expect(firstProvider.getFloorSpaces('exterior')).resolves.toMatchObject([ { name: '红花路' } ]) spaceName = '红花潭路' const reloadedProvider = createSgsSdkApiProvider() await expect(reloadedProvider.getFloorSpaces('exterior')).resolves.toMatchObject([ { name: '红花潭路' } ]) expect(request).toHaveBeenCalledTimes(2) }) it('reuses floor spaces within one provider session', async () => { const request = vi.fn((options: { success: (response: unknown) => void }) => { options.success({ statusCode: 200, header: { 'content-type': 'application/json' }, data: { code: 0, data: [{ id: 'space-1', name: '办公室', floorId: 'floor-1' }] } }) }) vi.stubGlobal('uni', { request }) const provider = createSgsSdkApiProvider() await provider.getFloorSpaces('floor-1') await provider.getFloorSpaces('floor-1') expect(request).toHaveBeenCalledTimes(1) }) it('reuses search collections already delivered by the floor bundle', async () => { const request = vi.fn((options: { url: string success: (response: unknown) => void }) => { expect(options.url).toContain('/gis/sdk/floors/floor-b2/bundle') options.success({ statusCode: 200, header: { 'content-type': 'application/json' }, data: { code: 0, data: { floor: { floorId: 'floor-b2', floorCode: 'L-2', floorName: 'B2' }, pois: [{ id: 'poi-b2', name: 'B2 点位', floorId: 'floor-b2' }], spaces: [{ id: 'space-b2', name: 'B2 空间', floorId: 'floor-b2' }], businessPois: [{ id: 'business-b2', name: 'B2 商户', floorId: 'floor-b2' }], navigablePlaces: [{ id: 'place-b2', name: 'B2 导航点', floorId: 'floor-b2' }] } } }) }) vi.stubGlobal('uni', { request }) const provider = createSgsSdkApiProvider() await provider.getFloorBundle('floor-b2') await expect(provider.getFloorPois('floor-b2')).resolves.toMatchObject([{ id: 'poi-b2' }]) await expect(provider.getFloorSpaces('floor-b2')).resolves.toMatchObject([{ id: 'space-b2' }]) await expect(provider.getFloorBusinessPois('floor-b2')).resolves.toMatchObject([{ id: 'business-b2' }]) await expect(provider.getNavigablePlaces('floor-b2')).resolves.toMatchObject([{ id: 'place-b2' }]) expect(request).toHaveBeenCalledTimes(1) }) it('treats empty search collections in a floor bundle as authoritative', async () => { const request = vi.fn((options: { url: string success: (response: unknown) => void }) => { expect(options.url).toContain('/gis/sdk/floors/floor-5/bundle') options.success({ statusCode: 200, header: { 'content-type': 'application/json' }, data: { code: 0, data: { floor: { floorId: 'floor-5', floorCode: 'L5', floorName: '5F' }, businessPois: [], navigablePlaces: [] } } }) }) vi.stubGlobal('uni', { request }) const provider = createSgsSdkApiProvider() await provider.getFloorBundle('floor-5') await expect(provider.getFloorBusinessPois('floor-5')).resolves.toEqual([]) await expect(provider.getNavigablePlaces('floor-5')).resolves.toEqual([]) expect(request).toHaveBeenCalledTimes(1) }) it('revalidates an old persisted empty floor collection', async () => { let responsePois: unknown[] = [] const request = vi.fn((options: { success: (response: unknown) => void }) => { options.success({ statusCode: 200, header: { 'content-type': 'application/json' }, data: { code: 0, data: responsePois } }) }) vi.stubGlobal('uni', { request }) await expect(createSgsSdkApiProvider().getFloorPois('floor-b2')).resolves.toEqual([]) responsePois = [{ id: 'poi-b2', name: 'B2 点位', floorId: 'floor-b2' }] await expect(createSgsSdkApiProvider().getFloorPois('floor-b2')).resolves.toMatchObject([ { id: 'poi-b2' } ]) expect(request).toHaveBeenCalledTimes(2) }) })