mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
6b6d971f07
The overview of a trip's tours decides for itself when it shows, which keeps the planner page hook inside its complexity and length limits, and adds nothing to the camera's key while there is no tour to frame. The elevation helper names its empty case for the strict type check, the self-host wording exemption for the retired Dawarich card goes, the day plan test reads the wrapping pills, and the new tests drop their non-null assertions and loops.
75 lines
3.4 KiB
TypeScript
75 lines
3.4 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('leaves the elevation model jitter of a flat walk out of its ascent', () => {
|
|
const analysis = analyzeRouteGeometry(JSON.stringify([
|
|
[45.44, 12.32, 2], [45.441, 12.32, 9], [45.442, 12.32, 1], [45.443, 12.32, 4], [45.444, 12.32, 3],
|
|
]))
|
|
expect(analysis?.maxEle).toBe(9)
|
|
expect(analysis?.gain).toBe(7)
|
|
expect(analysis?.loss).toBe(8)
|
|
})
|
|
|
|
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()
|
|
})
|
|
})
|