UNPKG

@sports-alliance/sports-lib

Version:

A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc

154 lines (153 loc) 7.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tss_calculator_1 = require("./tss-calculator"); const data_training_stress_score_method_1 = require("../../../data/data.training-stress-score-method"); describe('TssCalculator', () => { it('keeps power TSS parity with Coggan NP/IF/TSS behavior', () => { const result = tss_calculator_1.TssCalculator.calculatePowerTss({ totalDurationWithoutPauses: 120, functionalThresholdPower: 250, normalizedPower: 200, samples: [] }); const expectedIntensityFactor = 200 / 250; const expectedTss = (100 * (120 - 29) * 200 * expectedIntensityFactor) / (250 * 3600); expect(result).toBeTruthy(); expect(result.calculationMethod).toBe(data_training_stress_score_method_1.TrainingStressScoreMethod.POWER); expect(result.normalizedPower).toBeCloseTo(200, 6); expect(result.intensityFactor).toBeCloseTo(expectedIntensityFactor, 6); expect(result.trainingStressScore).toBeCloseTo(expectedTss, 6); }); it('calculates HR TSS using Banister TRIMP when max/rest HR exist', () => { const hr = 170; const samples = Array.from({ length: 3600 }, (_value, index) => ({ duration: index + 1, hr })); const result = tss_calculator_1.TssCalculator.calculateHrTss({ totalDurationWithoutPauses: 3600, lactateThresholdHR: 170, maxHeartRate: 190, restingHeartRate: 50, samples }); expect(result).toBeTruthy(); expect(result.calculationMethod).toBe(data_training_stress_score_method_1.TrainingStressScoreMethod.HR); expect(result.trainingStressScore).toBeCloseTo(100, 1); }); it('uses gender coefficient in Banister TRIMP and defaults unknown to male coefficient', () => { const samples = Array.from({ length: 3600 }, (_value, index) => ({ duration: index + 1, hr: 160 })); const male = tss_calculator_1.TssCalculator.calculateHrTss({ totalDurationWithoutPauses: 3600, lactateThresholdHR: 170, maxHeartRate: 190, restingHeartRate: 50, gender: 'male', samples }); const female = tss_calculator_1.TssCalculator.calculateHrTss({ totalDurationWithoutPauses: 3600, lactateThresholdHR: 170, maxHeartRate: 190, restingHeartRate: 50, gender: 'female', samples }); const unknown = tss_calculator_1.TssCalculator.calculateHrTss({ totalDurationWithoutPauses: 3600, lactateThresholdHR: 170, maxHeartRate: 190, restingHeartRate: 50, samples }); expect(male).toBeTruthy(); expect(female).toBeTruthy(); expect(unknown).toBeTruthy(); expect(female.trainingStressScore).toBeGreaterThan(male.trainingStressScore); expect(unknown.trainingStressScore).toBeCloseTo(male.trainingStressScore, 6); }); it('falls back to Edwards TRIMP when resting HR is missing', () => { const samples = Array.from({ length: 3600 }, (_value, index) => ({ duration: index + 1, hr: 160 })); const result = tss_calculator_1.TssCalculator.calculateHrTss({ totalDurationWithoutPauses: 3600, lactateThresholdHR: 160, maxHeartRate: 190, samples }); expect(result).toBeTruthy(); expect(result.calculationMethod).toBe(data_training_stress_score_method_1.TrainingStressScoreMethod.HR); expect(result.trainingStressScore).toBeCloseTo(100, 1); }); it('calculates pace TSS with Minetti grade adjustment and threshold normalization', () => { const samples = Array.from({ length: 3600 }, (_value, index) => ({ duration: index + 1, speed: 3, grade: 0 })); const result = tss_calculator_1.TssCalculator.calculatePaceTss({ totalDurationWithoutPauses: 3600, functionalThresholdPace: 3, samples }); expect(result).toBeTruthy(); expect(result.calculationMethod).toBe(data_training_stress_score_method_1.TrainingStressScoreMethod.PACE); expect(result.intensityFactor).toBeCloseTo(1, 1); expect(result.trainingStressScore).toBeCloseTo(100, 1); }); it('produces lower adjusted load uphill than downhill for same raw speed', () => { const uphill = tss_calculator_1.TssCalculator.calculatePaceTss({ totalDurationWithoutPauses: 1200, functionalThresholdPace: 3, samples: Array.from({ length: 1200 }, (_value, index) => ({ duration: index + 1, speed: 3, grade: 0.1 })) }); const downhill = tss_calculator_1.TssCalculator.calculatePaceTss({ totalDurationWithoutPauses: 1200, functionalThresholdPace: 3, samples: Array.from({ length: 1200 }, (_value, index) => ({ duration: index + 1, speed: 3, grade: -0.1 })) }); expect(uphill).toBeTruthy(); expect(downhill).toBeTruthy(); expect(downhill.trainingStressScore).toBeGreaterThan(uphill.trainingStressScore); }); it('calculates swim TSS from CSS/threshold speed with IF^3', () => { const result = tss_calculator_1.TssCalculator.calculateSwimTss({ totalDurationWithoutPauses: 3600, swimSpeed: 1.2, thresholdSwimSpeed: 1.2, samples: [] }); expect(result).toBeTruthy(); expect(result.calculationMethod).toBe(data_training_stress_score_method_1.TrainingStressScoreMethod.SWIM_PACE); expect(result.intensityFactor).toBeCloseTo(1, 6); expect(result.trainingStressScore).toBeCloseTo(100, 6); }); it('calculates normalized MET TSS and defaults thresholdMet to 10', () => { const estimatedMet = tss_calculator_1.TssCalculator.estimateMetScore(600, 75, 3600); const result = tss_calculator_1.TssCalculator.calculateMetTss({ totalDurationWithoutPauses: 3600, metScore: estimatedMet, samples: [] }); expect(estimatedMet).toBeCloseTo(8, 6); expect(result).toBeTruthy(); expect(result.calculationMethod).toBe(data_training_stress_score_method_1.TrainingStressScoreMethod.MET); expect(result.intensityFactor).toBeCloseTo(0.8, 6); expect(result.trainingStressScore).toBeCloseTo(64, 6); }); it('supports thresholdMet override for normalized MET TSS', () => { const result = tss_calculator_1.TssCalculator.calculateMetTss({ totalDurationWithoutPauses: 3600, metScore: 12, thresholdMet: 12, samples: [] }); expect(result).toBeTruthy(); expect(result.trainingStressScore).toBeCloseTo(100, 6); }); it('returns null when calculated TSS is outside valid range', () => { const result = tss_calculator_1.TssCalculator.calculateMetTss({ totalDurationWithoutPauses: 36000, metScore: 200, thresholdMet: 1, samples: [] }); expect(result).toBeNull(); }); });