import { describe, expect, it } from 'vitest'; import { parseGpxToTelemetryPoints, parseCsvToTelemetryPoints, synthesizeTelemetryTrack, generateRideGpx } from '../lib/telemetry-export'; import type { Ride } from '../components/app-cloud-data'; import { geographicSegments } from '../lib/telemetry-track'; // Sanitized MotorSignal bundle format; no production locations or account IDs. export const recordedGpx = ` 12180 25 `; export const summaryRide = { id: 'ride_sanitized', startedAt: new Date('2026-09-03T20:00:00Z'), movingTime: 301, distanceMiles: 15.66, topSpeedMph: 83.7, averageSpeed: 60, maxLeanLeft: 27, maxLeanRight: 26 } as Ride; describe('recorded replay coordinates', () => { it('never invents a route from summary metrics or a default start', () => { expect(synthesizeTelemetryTrack(summaryRide).length).toBe(0); }); it('preserves mixed attribute order, exact turns, chronological time and GPX segment breaks', () => { const points = parseGpxToTelemetryPoints(recordedGpx); expect(points.map(p => [p.latitude, p.longitude])).toEqual([[40,-74],[40.001,-73.999],[40.002,-73.998],[40.01,-73.99],[40.011,-73.989]]); expect(points.map(p => (p as typeof p & { segmentId: number }).segmentId)).toEqual([0,0,0,1,1]); expect(points[0].altitude).toBe(12); expect(points[0].speed).toBe(18); const exported = generateRideGpx(summaryRide, points); expect(exported.match(//g)).toHaveLength(2); }); it('preserves gaps from missing GPS CSV rows and invalid coordinates', () => { const csv = 'timestamp,latitude,longitude,speed,leanAngle\n2026-09-03T20:00:00Z,0,0,18,0\n2026-09-03T20:00:01Z,,,18,0\n2026-09-03T20:00:02Z,0.002,0.003,18,0\n2026-09-03T20:00:03Z,91,0,18,0'; const points = parseCsvToTelemetryPoints(csv); expect(points.map(p => [p.latitude,p.longitude])).toEqual([[0,0],[0.002,0.003]]); expect((points[1] as typeof points[1] & { segmentId: number }).segmentId).toBe(1); }); it('rejects missing/bad time instead of inventing current timestamps', () => { expect(parseGpxToTelemetryPoints('')).toEqual([]); }); it('passes exact latitude/longitude segments to the map without joining recording gaps',()=>{ const segments=geographicSegments(parseGpxToTelemetryPoints(recordedGpx)); expect(segments).toEqual([[[40,-74],[40.001,-73.999],[40.002,-73.998]],[[40.01,-73.99],[40.011,-73.989]]]); const invalid=recordedGpx.replace('',''); expect(geographicSegments(parseGpxToTelemetryPoints(invalid)).map(s=>s.length)).toEqual([1,1,2]); }); });