feat(vehicle): live-update single vehicle map
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { cleanup, render, waitFor } from '@testing-library/react';
|
||||
import { afterEach, expect, test, vi } from 'vitest';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
import { api } from '../../api/client';
|
||||
import type { VehicleDetail, VehicleRealtimeRow } from '../../api/types';
|
||||
import { ROUTER_FUTURE } from '../routing/routerConfig';
|
||||
import VehiclePage from './VehiclePage';
|
||||
|
||||
const fleetMapVehicles = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('../map/FleetMap', () => ({
|
||||
FleetMap: ({ vehicles }: { vehicles: VehicleRealtimeRow[] }) => {
|
||||
fleetMapVehicles(vehicles);
|
||||
return <div data-testid="fleet-map" />;
|
||||
}
|
||||
}));
|
||||
|
||||
vi.mock('../auth/AuthGate', () => ({
|
||||
usePlatformSession: () => ({ session: { name: 'test-viewer', role: 'viewer', authMode: 'enforce' } })
|
||||
}));
|
||||
|
||||
const initialRealtime = {
|
||||
vin: 'LTEST000000000001', plate: '粤A12345', phone: '', oem: '', protocols: ['JT808'], sourceStatus: [],
|
||||
sourceCount: 1, onlineSourceCount: 1, online: true, bindingStatus: 'bound', primaryProtocol: 'JT808',
|
||||
longitude: 113.26, latitude: 23.13, speedKmh: 20, socPercent: 80, totalMileageKm: 1000,
|
||||
lastSeen: '2026-07-16 10:00:00', reportIntervalMs: 30_000
|
||||
} satisfies VehicleRealtimeRow;
|
||||
|
||||
const detail = {
|
||||
vin: initialRealtime.vin,
|
||||
lookupKey: initialRealtime.vin,
|
||||
lookupResolved: true,
|
||||
realtimeSummary: initialRealtime,
|
||||
sources: ['JT808'],
|
||||
sourceStatus: [],
|
||||
realtime: [],
|
||||
history: { items: [], total: 0, limit: 20, offset: 0 },
|
||||
raw: { items: [], total: 0, limit: 20, offset: 0 },
|
||||
mileage: { items: [], total: 0, limit: 20, offset: 0 },
|
||||
quality: { items: [], total: 0, limit: 20, offset: 0 }
|
||||
} satisfies VehicleDetail;
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.restoreAllMocks();
|
||||
fleetMapVehicles.mockReset();
|
||||
});
|
||||
|
||||
test('polls lightweight single-vehicle realtime data and passes its report interval to the map', async () => {
|
||||
const movedRealtime = { ...initialRealtime, longitude: 113.28, latitude: 23.15, lastSeen: '2026-07-16 10:00:30' };
|
||||
vi.spyOn(api, 'vehicleDetail').mockResolvedValue(detail);
|
||||
const realtimeSpy = vi.spyOn(api, 'vehicleRealtime').mockResolvedValue({ items: [movedRealtime], total: 1, limit: 1, offset: 0 });
|
||||
vi.spyOn(api, 'latestTelemetry').mockResolvedValue({ values: [], categories: [], scannedFrames: 0 } as never);
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
|
||||
render(<QueryClientProvider client={client}><MemoryRouter initialEntries={[`/vehicles/${initialRealtime.vin}`]} future={ROUTER_FUTURE}><Routes><Route path="/vehicles/:vin" element={<VehiclePage />} /></Routes></MemoryRouter></QueryClientProvider>);
|
||||
|
||||
await waitFor(() => expect(realtimeSpy).toHaveBeenCalledTimes(1));
|
||||
const realtimeQuery = client.getQueryCache().find({ queryKey: ['vehicle-detail-realtime', initialRealtime.vin] });
|
||||
expect((realtimeQuery?.options as { refetchInterval?: number }).refetchInterval).toBe(10_000);
|
||||
const params = realtimeSpy.mock.calls[0][0];
|
||||
expect(params).toBeDefined();
|
||||
expect(params!.get('keywords')).toBe(initialRealtime.vin);
|
||||
expect(params!.get('limit')).toBe('1');
|
||||
await waitFor(() => expect(fleetMapVehicles).toHaveBeenLastCalledWith([
|
||||
expect.objectContaining({ longitude: 113.28, latitude: 23.15, reportIntervalMs: 30_000 })
|
||||
]));
|
||||
});
|
||||
Reference in New Issue
Block a user