import { describe, it, expect } from 'vitest' import { reorderStops, computeTotals, buildNavigationLinks, isStopLocated, formatDistance, formatDuration, formatTime, type PlanningStop, } from '../useTourPlanning' /** Fabrique une etape de planification minimale pour les tests. */ function makeStop(overrides: Partial = {}): PlanningStop { return { id: overrides.id ?? 1, tierType: overrides.tierType ?? 'client', tierId: overrides.tierId ?? null, addressId: overrides.addressId ?? null, customLabel: null, customAddress: null, customLatitude: null, customLongitude: null, position: overrides.position ?? 0, visitMinutes: overrides.visitMinutes ?? null, legDistanceM: overrides.legDistanceM ?? null, legDurationS: overrides.legDurationS ?? null, eta: overrides.eta ?? null, label: overrides.label ?? 'Étape', displayAddress: overrides.displayAddress ?? '', latitude: overrides.latitude ?? null, longitude: overrides.longitude ?? null, } } describe('reorderStops', () => { it('deplace une etape et renumerote les positions de maniere contigue', () => { const stops = [ makeStop({ id: 1, position: 0, label: 'A' }), makeStop({ id: 2, position: 1, label: 'B' }), makeStop({ id: 3, position: 2, label: 'C' }), ] // Deplace C (index 2) en tete (index 0). const result = reorderStops(stops, 2, 0) expect(result.map(s => s.label)).toEqual(['C', 'A', 'B']) expect(result.map(s => s.position)).toEqual([0, 1, 2]) }) it('ne mute pas le tableau source', () => { const stops = [makeStop({ id: 1, position: 0 }), makeStop({ id: 2, position: 1 })] reorderStops(stops, 0, 1) expect(stops.map(s => s.id)).toEqual([1, 2]) }) it('retourne une copie inchangee si un index est hors borne', () => { const stops = [makeStop({ id: 1, position: 0 })] const result = reorderStops(stops, 0, 5) expect(result.map(s => s.id)).toEqual([1]) }) }) describe('computeTotals', () => { it('somme distances/trajets et ajoute les visites (defaut + specifique)', () => { const stops = [ // 1re etape : pas de leg (point de depart). Visite = defaut 30 min. makeStop({ id: 1, legDistanceM: null, legDurationS: null }), // 2e : 10 km / 12 min de trajet, visite specifique 15 min. makeStop({ id: 2, legDistanceM: 10_000, legDurationS: 720, visitMinutes: 15 }), // 3e : 5 km / 6 min, visite par defaut. makeStop({ id: 3, legDistanceM: 5_000, legDurationS: 360, visitMinutes: null }), ] const totals = computeTotals(stops, 30) expect(totals.totalDistanceM).toBe(15_000) expect(totals.travelDurationS).toBe(1_080) // Visites : 30 + 15 + 30 = 75 min = 4500 s. expect(totals.visitDurationS).toBe(4_500) expect(totals.totalDurationS).toBe(1_080 + 4_500) expect(totals.visitCount).toBe(3) }) it('renvoie des totaux nuls pour une tournee vide', () => { const totals = computeTotals([], 30) expect(totals.totalDistanceM).toBe(0) expect(totals.totalDurationS).toBe(0) expect(totals.visitCount).toBe(0) }) }) describe('buildNavigationLinks', () => { it('construit les trois deep links Waze/Google/Apple', () => { const links = buildNavigationLinks({ latitude: 47.218, longitude: -1.553 }) expect(links).not.toBeNull() expect(links!.waze).toBe('https://waze.com/ul?ll=47.218,-1.553&navigate=yes') expect(links!.google).toBe('https://www.google.com/maps/dir/?api=1&destination=47.218,-1.553') expect(links!.apple).toBe('https://maps.apple.com/?daddr=47.218,-1.553') }) it('retourne null sans coordonnees (etape a geolocaliser)', () => { expect(buildNavigationLinks(null)).toBeNull() expect(buildNavigationLinks({ latitude: 47.2 })).toBeNull() expect(buildNavigationLinks({ latitude: null, longitude: null })).toBeNull() }) }) describe('isStopLocated', () => { it('distingue une etape geolocalisee d\'une etape sans coordonnees', () => { expect(isStopLocated({ latitude: 47.2, longitude: -1.5 })).toBe(true) expect(isStopLocated({ latitude: null, longitude: null })).toBe(false) }) }) describe('formatteurs', () => { it('formate distances et durees', () => { expect(formatDistance(850)).toBe('850 m') expect(formatDistance(12_340)).toBe('12,3 km') expect(formatDistance(null)).toBe('—') expect(formatDuration(1_500)).toBe('25 min') expect(formatDuration(5_100)).toBe('1 h 25') expect(formatDuration(null)).toBe('—') }) it('extrait l\'heure HH:MM d\'une chaine ISO', () => { expect(formatTime('1970-01-01T08:30:00+00:00')).toBe('08:30') expect(formatTime(null)).toBe('—') }) })