Files
TREK/client/src/utils/routeGeometry.test.ts
T
2026-10-04 12:59:55 +02:00

66 lines
3.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { analyzeRouteGeometry, focusRouteProfileAtDistance, parseRenderableRouteGeometry } from './routeGeometry'
describe('analyzeRouteGeometry', () => {
it('shares a validated rendering parser that retains valid elevation values', () => {
expect(parseRenderableRouteGeometry('[[48,11,512.125],[48.01,11.02,520.75]]'))
.toEqual([[48, 11, 512.125], [48.01, 11.02, 520.75]])
})
it('derives distance, elevation extrema, gain, loss and cumulative-distance samples together', () => {
const analysis = analyzeRouteGeometry(JSON.stringify([
[0, 0, 100],
[0, 0.01, 130],
[0, 0.03, 110],
]))
expect(analysis).not.toBeNull()
expect(analysis!.routeCoordinates).toEqual([[0, 0], [0, 0.01], [0, 0.03]])
expect(analysis!.distanceKm).toBeCloseTo(3.3358, 3)
expect(analysis!.minEle).toBe(100)
expect(analysis!.maxEle).toBe(130)
expect(analysis!.gain).toBe(30)
expect(analysis!.loss).toBe(20)
expect(analysis!.distanceIndexedProfileSamples).toHaveLength(3)
expect(analysis!.distanceIndexedProfileSamples[1]).toMatchObject({ lat: 0, lng: 0.01 })
expect(analysis!.distanceIndexedProfileSamples[1].distanceMeters).toBeCloseTo(1111.95, 1)
expect(analysis!.distanceIndexedProfileSamples[2].distanceMeters).toBeCloseTo(3335.85, 1)
})
it('maps route endpoints and interpolates focus between prepared samples', () => {
const samples = [
{ distanceMeters: 0, elevationMeters: 100, lat: 10, lng: 20 },
{ distanceMeters: 100, elevationMeters: 200, lat: 12, lng: 24 },
{ distanceMeters: 300, elevationMeters: 300, lat: 14, lng: 28 },
]
expect(focusRouteProfileAtDistance(samples, -20)).toMatchObject({ distanceMeters: 0, elevationMeters: 100, lat: 10, lng: 20, sampleIndex: 0 })
expect(focusRouteProfileAtDistance(samples, 150)).toMatchObject({ distanceMeters: 150, elevationMeters: 225, lat: 12.5, lng: 25, sampleIndex: 1 })
expect(focusRouteProfileAtDistance(samples, 500)).toMatchObject({ distanceMeters: 300, elevationMeters: 300, lat: 14, lng: 28, sampleIndex: 2 })
})
it('does not create geographic focus for samples without coordinates', () => {
expect(focusRouteProfileAtDistance([
{ distanceMeters: 0, elevationMeters: 100 },
{ distanceMeters: 10, elevationMeters: 110 },
], 5)).toBeNull()
})
it('keeps distance but omits all elevation outputs when any point lacks elevation', () => {
const analysis = analyzeRouteGeometry(JSON.stringify([
[48, 11, 500],
[48.01, 11.01],
]))
expect(analysis?.distanceKm).toBeGreaterThan(0)
expect(analysis?.minEle).toBeNull()
expect(analysis?.maxEle).toBeNull()
expect(analysis?.gain).toBeNull()
expect(analysis?.loss).toBeNull()
expect(analysis?.distanceIndexedProfileSamples).toEqual([])
})
it.each([undefined, null, '', 'not json', '[]', '[[0,0]]', '[[0,"bad"],[1,1]]'])('returns null for unusable geometry %s', geometry => {
expect(analyzeRouteGeometry(geometry)).toBeNull()
})
})