running-tools

A collection of tools for runners and their coaches
git clone https://git.ashermorgan.net/running-tools/
Log | Files | Refs | README

commit f8903eefac949b7eebf6e2c3a33bb6d55e2af521
parent 033fc052c51ba689bd8e44ccf370f9262f951760
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Sun, 13 Jul 2025 12:38:41 -0700

Hide riegel exponent option when not applicable

Also rename RacePredictionModel enum to RacePredictionModels.

Diffstat:
Msrc/components/AdvancedOptionsInput.vue | 15+++++++++------
Msrc/core/calculators.ts | 4++--
Msrc/core/racePrediction.ts | 26+++++++++++++-------------
Mtests/unit/components/AdvancedOptionsInput.spec.js | 37+++++++++++++++++++++++++++++++++++++
4 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/src/components/AdvancedOptionsInput.vue b/src/components/AdvancedOptionsInput.vue @@ -27,15 +27,17 @@ <div v-if="props.type === Calculators.Race || props.type === Calculators.Workout"> Prediction Model: <select v-model="(options as RaceOptions).model" aria-label="Prediction model"> - <option value="AverageModel">Average</option> - <option value="PurdyPointsModel">Purdy Points Model</option> - <option value="VO2MaxModel">V&#775;O&#8322; Max Model</option> - <option value="CameronModel">Cameron's Model</option> - <option value="RiegelModel">Riegel's Model</option> + <option :value="RacePredictionModels.AverageModel">Average</option> + <option :value="RacePredictionModels.PurdyPointsModel">Purdy Points Model</option> + <option :value="RacePredictionModels.VO2MaxModel">V&#775;O&#8322; Max Model</option> + <option :value="RacePredictionModels.CameronModel">Cameron's Model</option> + <option :value="RacePredictionModels.RiegelModel">Riegel's Model</option> </select> </div> - <div v-if="props.type === Calculators.Race || props.type === Calculators.Workout"> + <div v-if="props.type === Calculators.Race || props.type === Calculators.Workout" + v-show="(options as RaceOptions).model == RacePredictionModels.AverageModel || + (options as RaceOptions).model == RacePredictionModels.RiegelModel"> Riegel Exponent: <decimal-input v-model="(options as RaceOptions).riegelExponent" aria-label="Riegel exponent" :min="1" :max="1.3" :digits="2" :step="0.01"/> @@ -46,6 +48,7 @@ <script setup lang="ts"> import { Calculators } from '@/core/calculators'; import type { StandardOptions, RaceOptions, WorkoutOptions } from '@/core/calculators'; +import { RacePredictionModels } from '@/core/racePrediction'; import type { TargetSets } from '@/core/targets'; import { UnitSystems } from '@/core/units'; diff --git a/src/core/calculators.ts b/src/core/calculators.ts @@ -38,7 +38,7 @@ export interface StandardOptions { selectedTargetSet: string, } export interface RaceOptions extends StandardOptions { - model: racePrediction.RacePredictionModel, + model: racePrediction.RacePredictionModels, riegelExponent: number, }; export interface WorkoutOptions extends RaceOptions { @@ -86,7 +86,7 @@ export const defaultPaceOptions: StandardOptions = { selectedTargetSet: '_pace_targets', }; export const defaultRaceOptions: RaceOptions = { - model: racePrediction.RacePredictionModel.AverageModel, + model: racePrediction.RacePredictionModels.AverageModel, riegelExponent: 1.06, selectedTargetSet: '_race_targets', }; diff --git a/src/core/racePrediction.ts b/src/core/racePrediction.ts @@ -5,7 +5,7 @@ /* * The available race prediction models */ -export enum RacePredictionModel { +export enum RacePredictionModels { AverageModel = 'AverageModel', PurdyPointsModel = 'PurdyPointsModel', VO2MaxModel = 'VO2MaxModel', @@ -442,19 +442,19 @@ const AverageModel = { * @param {number} c The value of the exponent in Pete Riegel's Model */ export function predictTime(d1: number, t1: number, d2: number, - model: RacePredictionModel = RacePredictionModel.AverageModel, + model: RacePredictionModels = RacePredictionModels.AverageModel, c: number = 1.06): number { switch (model) { default: - case RacePredictionModel.AverageModel: + case RacePredictionModels.AverageModel: return AverageModel.predictTime(d1, t1, d2, c); - case RacePredictionModel.PurdyPointsModel: + case RacePredictionModels.PurdyPointsModel: return PurdyPointsModel.predictTime(d1, t1, d2); - case RacePredictionModel.VO2MaxModel: + case RacePredictionModels.VO2MaxModel: return VO2MaxModel.predictTime(d1, t1, d2); - case RacePredictionModel.RiegelModel: + case RacePredictionModels.RiegelModel: return RiegelModel.predictTime(d1, t1, d2, c); - case RacePredictionModel.CameronModel: + case RacePredictionModels.CameronModel: return CameronModel.predictTime(d1, t1, d2); } } @@ -468,19 +468,19 @@ export function predictTime(d1: number, t1: number, d2: number, * @param {number} c The value of the exponent in Pete Riegel's Model */ export function predictDistance(t1: number, d1: number, t2: number, - model: RacePredictionModel = RacePredictionModel.AverageModel, + model: RacePredictionModels = RacePredictionModels.AverageModel, c: number = 1.06) { switch (model) { default: - case RacePredictionModel.AverageModel: + case RacePredictionModels.AverageModel: return AverageModel.predictDistance(t1, d1, t2, c); - case RacePredictionModel.PurdyPointsModel: + case RacePredictionModels.PurdyPointsModel: return PurdyPointsModel.predictDistance(t1, d1, t2); - case RacePredictionModel.VO2MaxModel: + case RacePredictionModels.VO2MaxModel: return VO2MaxModel.predictDistance(t1, d1, t2); - case RacePredictionModel.RiegelModel: + case RacePredictionModels.RiegelModel: return RiegelModel.predictDistance(t1, d1, t2, c); - case RacePredictionModel.CameronModel: + case RacePredictionModels.CameronModel: return CameronModel.predictDistance(t1, d1, t2); } } diff --git a/tests/unit/components/AdvancedOptionsInput.spec.js b/tests/unit/components/AdvancedOptionsInput.spec.js @@ -85,6 +85,43 @@ test('should be correctly render race options according to props', () => { expect(wrapper.find('select[aria-label="Prediction model"]').element.value).to .equal('PurdyPointsModel'); expect(wrapper.findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(1.2); + expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false); +}); + +test('should render riegel exponent field only for supported race prediction models', async () => { + // Initialize component + const wrapper = shallowMount(AdvancedOptionsInput, { + propsData: { + defaultUnitSystem: 'metric', + options: { + model: 'AverageModel', + riegelExponent: 1.2, + selectedTargetSet: '_new', + }, + type: 'race', + targetSets: {}, + }, + attachTo: document.body, + }); + + // Assert field is visible for Average model + expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(true); + + // Assert field is not visible for Purdy Points model + await wrapper.find('select[aria-label="Prediction model"]').setValue('PurdyPointsModel'); + expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false); + + // Assert field is not visible for VO2 Max model + await wrapper.find('select[aria-label="Prediction model"]').setValue('VO2MaxModel'); + expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false); + + // Assert field is not visible for Cameron model + await wrapper.find('select[aria-label="Prediction model"]').setValue('CameronModel'); + expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false); + + // Assert field is not visible for Riegel model + await wrapper.find('select[aria-label="Prediction model"]').setValue('RiegelModel'); + expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(true); }); test('should be correctly render split options according to props', () => {