commit edcfdfbc9fa27f940f1b3accde172f5e96b490b7
parent 3ebace2a5a49947c003efcea22c3e8be79b0e031
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date: Sun, 6 Jul 2025 15:06:19 -0700
Extract advanced calculator options into component
Diffstat:
13 files changed, 568 insertions(+), 227 deletions(-)
diff --git a/src/components/AdvancedOptionsInput.vue b/src/components/AdvancedOptionsInput.vue
@@ -0,0 +1,88 @@
+<template>
+ <div>
+ Default units:
+ <select v-model="defaultUnitSystem" aria-label="Default units">
+ <option value="imperial">Miles</option>
+ <option value="metric">Kilometers</option>
+ </select>
+ </div>
+
+ <div>
+ Target Set:
+ <target-set-selector :setType="props.type === Calculators.Workout ? TargetSetTypes.Workout :
+ (props.type === Calculators.Split ? TargetSetTypes.Split : TargetSetTypes.Standard)"
+ v-model:selected-target-set="options.selectedTargetSet"
+ v-model:target-sets="targetSets" :default-unit-system="defaultUnitSystem"
+ :customWorkoutNames="props.type === Calculators.Workout ?
+ (options as WorkoutOptions).customTargetNames : false"/>
+ </div>
+
+ <div v-if="props.type === Calculators.Workout">
+ Target Name Customization:
+ <select v-model="(options as WorkoutOptions).customTargetNames"
+ aria-label="Target name customization">
+ <option :value="false">Disabled</option>
+ <option :value="true">Enabled</option>
+ </select>
+ </div>
+
+ <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̇O₂ Max Model</option>
+ <option value="CameronModel">Cameron's Model</option>
+ <option value="RiegelModel">Riegel's Model</option>
+ </select>
+ </div>
+
+ <div v-if="props.type === Calculators.Race || props.type === Calculators.Workout">
+ Riegel Exponent:
+ <decimal-input v-model="(options as RaceOptions).riegelExponent"
+ aria-label="Riegel exponent" :min="1" :max="1.3" :digits="2" :step="0.01"/>
+ (default: 1.06)
+ </div>
+</template>
+
+<script setup lang="ts">
+import { Calculators } from '@/utils/calculators';
+import type { CalculatorOptions, RaceOptions, WorkoutOptions } from '@/utils/calculators';
+import { TargetSetTypes } from '@/utils/targets';
+import type { TargetSets } from '@/utils/targets';
+import { UnitSystems } from '@/utils/units';
+
+import DecimalInput from '@/components/DecimalInput.vue';
+import TargetSetSelector from '@/components/TargetSetSelector.vue';
+
+import useObjectModel from '@/composables/useObjectModel';
+
+/*
+ * The default unit system
+ */
+const defaultUnitSystem = defineModel<UnitSystems>('defaultUnitSystem');
+
+const props = defineProps<{
+ /*
+ * The calculator options
+ */
+ options: CalculatorOptions,
+
+ /*
+ * The calculator type
+ */
+ type: Calculators,
+
+ /*
+ * The calculator target sets
+ */
+ targetSets: TargetSets,
+}>();
+
+// Generate internal refs tied to options and targetSets props
+const emit = defineEmits(['update:options', 'update:targetSets']);
+const options = useObjectModel<CalculatorOptions>(() => props.options, (x) =>
+ emit('update:options', x));
+const targetSets = useObjectModel<TargetSets>(() => props.targetSets, (x) =>
+ emit('update:targetSets', x));
+</script>
diff --git a/src/utils/calculators.ts b/src/utils/calculators.ts
@@ -7,11 +7,14 @@ import { DistanceUnits, DistanceUnitData, UnitSystems, convertDistance,
getDefaultDistanceUnit } from '@/utils/units';
import type { DistanceTime } from '@/utils/units';
+/*
+ * The four main calculators (batch and unit calculators not included)
+ */
export enum Calculators {
- Pace,
- Race,
- Split,
- Workout,
+ Pace = 'pace',
+ Race = 'race',
+ Split = 'split',
+ Workout = 'workout',
}
/*
@@ -37,6 +40,7 @@ export interface RaceOptions extends StandardOptions {
export interface WorkoutOptions extends RaceOptions {
customTargetNames: boolean,
};
+export type CalculatorOptions = StandardOptions | RaceOptions | WorkoutOptions;
/*
* The two possible result fields of a target result: "key" and "value"
diff --git a/src/views/BatchCalculator.vue b/src/views/BatchCalculator.vue
@@ -27,32 +27,8 @@
<summary>
<h2>Advanced Options</h2>
</summary>
- <div>
- Default units:
- <select v-model="defaultUnitSystem" aria-label="Default units">
- <option value="imperial">Miles</option>
- <option value="metric">Kilometers</option>
- </select>
- </div>
- <div>
- Target Set:
- <target-set-selector v-model:selectedTargetSet="calcOptions.selectedTargetSet"
- :set-type="options.calculator === BatchCompatableCalculators.Workout ?
- targetUtils.TargetSetTypes.Workout : targetUtils.TargetSetTypes.Standard"
- v-model:targetSets="targetSets" :default-unit-system="defaultUnitSystem"
- :customWorkoutNames="options.calculator === BatchCompatableCalculators.Workout ?
- (calcOptions as WorkoutOptions).customTargetNames : false"/>
- </div>
- <div v-if="options.calculator === 'workout'">
- Target Name Customization:
- <select v-model="(calcOptions as WorkoutOptions).customTargetNames"
- aria-label="Target name customization">
- <option :value="false">Disabled</option>
- <option :value="true">Enabled</option>
- </select>
- </div>
- <race-options-input v-if="options.calculator !== BatchCompatableCalculators.Pace"
- v-model="calcOptions as RaceOptions"/>
+ <advanced-options-input v-model:defaultUnitSystem="defaultUnitSystem"
+ v-model:options="calcOptions" v-model:targetSets="targetSets" :type="options.calculator"/>
</details>
<h2>Batch Results</h2>
@@ -74,29 +50,19 @@ import * as targetUtils from '@/utils/targets';
import { DistanceUnits, UnitSystems, detectDefaultUnitSystem } from '@/utils/units';
import type { Distance, DistanceTime } from '@/utils/units';
+import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
import DoubleOutputTable from '@/components/DoubleOutputTable.vue';
import IntegerInput from '@/components/IntegerInput.vue';
import PaceInput from '@/components/PaceInput.vue';
-import RaceOptionsInput from '@/components/RaceOptionsInput.vue';
-import TargetSetSelector from '@/components/TargetSetSelector.vue';
import TimeInput from '@/components/TimeInput.vue';
import useStorage from '@/composables/useStorage';
/*
- * The calculators that may be used from within the batch calculator
- */
-enum BatchCompatableCalculators {
- Pace = 'pace',
- Race = 'race',
- Workout = 'workout',
-};
-
-/*
* The type for options specific to the batch calculator
*/
interface BatchCalculatorOptions {
- calculator: BatchCompatableCalculators,
+ calculator: calcUtils.Calculators,
increment: number,
rows: number,
};
@@ -114,7 +80,7 @@ const input = useStorage<DistanceTime>('batch-calculator-input', {
* The batch input options
*/
const options = useStorage<BatchCalculatorOptions>('batch-calculator-options', {
- calculator: BatchCompatableCalculators.Workout,
+ calculator: calcUtils.Calculators.Workout,
increment: 15,
rows: 20,
});
@@ -180,30 +146,30 @@ const inputTimes = computed<Array<number>>(() => {
const targetSets = computed<targetUtils.TargetSets>({
get: () => {
switch (options.value.calculator) {
- case (BatchCompatableCalculators.Pace): {
+ case (calcUtils.Calculators.Pace): {
return paceTargetSets.value;
}
- case (BatchCompatableCalculators.Race): {
+ case (calcUtils.Calculators.Race): {
return raceTargetSets.value;
}
default:
- case (BatchCompatableCalculators.Workout): {
+ case (calcUtils.Calculators.Workout): {
return workoutTargetSets.value;
}
}
},
set: (newValue: targetUtils.TargetSets) => {
switch (options.value.calculator) {
- case (BatchCompatableCalculators.Pace): {
+ case (calcUtils.Calculators.Pace): {
paceTargetSets.value = newValue as targetUtils.StandardTargetSets;
break;
}
- case (BatchCompatableCalculators.Race): {
+ case (calcUtils.Calculators.Race): {
raceTargetSets.value = newValue as targetUtils.StandardTargetSets;
break;
}
default:
- case (BatchCompatableCalculators.Workout): {
+ case (calcUtils.Calculators.Workout): {
workoutTargetSets.value = newValue as targetUtils.WorkoutTargetSets;
break;
}
@@ -217,30 +183,30 @@ const targetSets = computed<targetUtils.TargetSets>({
const calcOptions = computed<StandardOptions | RaceOptions | WorkoutOptions>({
get: () => {
switch (options.value.calculator) {
- case (BatchCompatableCalculators.Pace): {
+ case (calcUtils.Calculators.Pace): {
return paceOptions.value;
}
- case (BatchCompatableCalculators.Race): {
+ case (calcUtils.Calculators.Race): {
return raceOptions.value;
}
default:
- case (BatchCompatableCalculators.Workout): {
+ case (calcUtils.Calculators.Workout): {
return workoutOptions.value;
}
}
},
set: (newValue: StandardOptions | RaceOptions | WorkoutOptions) => {
switch(options.value.calculator) {
- case (BatchCompatableCalculators.Pace): {
+ case (calcUtils.Calculators.Pace): {
paceOptions.value = newValue as StandardOptions;
break;
}
- case (BatchCompatableCalculators.Race): {
+ case (calcUtils.Calculators.Race): {
raceOptions.value = newValue as RaceOptions;
break;
}
default:
- case (BatchCompatableCalculators.Workout): {
+ case (calcUtils.Calculators.Workout): {
workoutOptions.value = newValue as WorkoutOptions;
break;
}
@@ -253,15 +219,15 @@ const calcOptions = computed<StandardOptions | RaceOptions | WorkoutOptions>({
*/
const calculateResult = computed<(x: DistanceTime, y: targetUtils.Target) => TargetResult>(() => {
switch(options.value.calculator) {
- case (BatchCompatableCalculators.Pace): {
+ case (calcUtils.Calculators.Pace): {
return (x,y) => calcUtils.calculatePaceResults(x, y, defaultUnitSystem.value, false);
}
- case (BatchCompatableCalculators.Race): {
+ case (calcUtils.Calculators.Race): {
return (x,y) => calcUtils.calculateRaceResults(x, y, raceOptions.value,
defaultUnitSystem.value, false);
}
default:
- case (BatchCompatableCalculators.Workout): {
+ case (calcUtils.Calculators.Workout): {
return (x,y) => calcUtils.calculateWorkoutResults(x, y as targetUtils.WorkoutTarget,
workoutOptions.value, false);
}
diff --git a/src/views/PaceCalculator.vue b/src/views/PaceCalculator.vue
@@ -9,18 +9,8 @@
<summary>
<h2>Advanced Options</h2>
</summary>
- <div>
- Default units:
- <select v-model="defaultUnitSystem" aria-label="Default units">
- <option value="imperial">Miles</option>
- <option value="metric">Kilometers</option>
- </select>
- </div>
- <div>
- Target Set:
- <target-set-selector v-model:selectedTargetSet="options.selectedTargetSet"
- v-model:targetSets="targetSets" :default-unit-system="defaultUnitSystem"/>
- </div>
+ <advanced-options-input v-model:defaultUnitSystem="defaultUnitSystem"
+ v-model:options="options" v-model:targetSets="targetSets" :type="Calculators.Pace"/>
</details>
<h2>Equivalent Paces</h2>
@@ -32,16 +22,16 @@
</template>
<script setup lang="ts">
-import { calculatePaceResults } from '@/utils/calculators';
+import { Calculators, calculatePaceResults } from '@/utils/calculators';
import type { StandardOptions } from '@/utils/calculators';
import { defaultTargetSets } from '@/utils/targets';
import type { StandardTargetSets } from '@/utils/targets';
import { DistanceUnits, UnitSystems, detectDefaultUnitSystem } from '@/utils/units';
import type { DistanceTime } from '@/utils/units';
+import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
import PaceInput from '@/components/PaceInput.vue';
import SingleOutputTable from '@/components/SingleOutputTable.vue';
-import TargetSetSelector from '@/components/TargetSetSelector.vue';
import useStorage from '@/composables/useStorage';
diff --git a/src/views/RaceCalculator.vue b/src/views/RaceCalculator.vue
@@ -26,19 +26,8 @@
<summary>
<h2>Advanced Options</h2>
</summary>
- <div>
- Default units:
- <select v-model="defaultUnitSystem" aria-label="Default units">
- <option value="imperial">Miles</option>
- <option value="metric">Kilometers</option>
- </select>
- </div>
- <div>
- Target Set:
- <target-set-selector v-model:selectedTargetSet="options.selectedTargetSet"
- v-model:targetSets="targetSets" :default-unit-system="defaultUnitSystem"/>
- </div>
- <race-options-input v-model="options"/>
+ <advanced-options-input v-model:defaultUnitSystem="defaultUnitSystem"
+ v-model:options="options" v-model:targetSets="targetSets" :type="Calculators.Race"/>
</details>
<h2>Equivalent Race Results</h2>
@@ -52,7 +41,7 @@
<script setup lang="ts">
import { computed } from 'vue';
-import { calculateRaceResults, calculateRaceStats } from '@/utils/calculators';
+import { Calculators, calculateRaceResults, calculateRaceStats } from '@/utils/calculators';
import type { RaceOptions, RaceStats } from '@/utils/calculators';
import { formatNumber } from '@/utils/format';
import { RacePredictionModel } from '@/utils/races';
@@ -61,10 +50,9 @@ import type { StandardTargetSets } from '@/utils/targets';
import { DistanceUnits, UnitSystems, detectDefaultUnitSystem } from '@/utils/units';
import type { DistanceTime } from '@/utils/units';
+import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
import PaceInput from '@/components/PaceInput.vue';
-import RaceOptionsInput from '@/components/RaceOptionsInput.vue';
import SingleOutputTable from '@/components/SingleOutputTable.vue';
-import TargetSetSelector from '@/components/TargetSetSelector.vue';
import useStorage from '@/composables/useStorage';
diff --git a/src/views/SplitCalculator.vue b/src/views/SplitCalculator.vue
@@ -1,20 +1,8 @@
<template>
<div class="calculator">
<div class="input">
- <div class="default-units">
- Default units:
- <select v-model="defaultUnitSystem" aria-label="Default units">
- <option value="imperial">Miles</option>
- <option value="metric">Kilometers</option>
- </select>
- </div>
-
- <div class="target-set">
- Target Set:
- <target-set-selector v-model:selectedTargetSet="options.selectedTargetSet"
- :set-type="TargetSetTypes.Split" v-model:targetSets="targetSets"
- :default-unit-system="defaultUnitSystem"/>
- </div>
+ <advanced-options-input v-model:defaultUnitSystem="defaultUnitSystem"
+ v-model:options="options" v-model:targetSets="targetSets" :type="Calculators.Split"/>
</div>
<div class="output">
@@ -26,14 +14,14 @@
<script setup lang="ts">
import { computed } from 'vue';
+import { Calculators } from '@/utils/calculators';
import type { StandardOptions } from '@/utils/calculators';
import { defaultTargetSets } from '@/utils/targets';
-import { TargetSetTypes } from '@/utils/targets';
import type { SplitTargetSet, SplitTargetSets } from '@/utils/targets';
import { UnitSystems, detectDefaultUnitSystem } from '@/utils/units';
+import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
import SplitOutputTable from '@/components/SplitOutputTable.vue';
-import TargetSetSelector from '@/components/TargetSetSelector.vue';
import useStorage from '@/composables/useStorage';
diff --git a/src/views/WorkoutCalculator.vue b/src/views/WorkoutCalculator.vue
@@ -9,27 +9,8 @@
<summary>
<h2>Advanced Options</h2>
</summary>
- <div>
- Default units:
- <select v-model="defaultUnitSystem" aria-label="Default units">
- <option value="imperial">Miles</option>
- <option value="metric">Kilometers</option>
- </select>
- </div>
- <div>
- Target Set:
- <target-set-selector v-model:selectedTargetSet="options.selectedTargetSet"
- :set-type="TargetSetTypes.Workout" :customWorkoutNames="options.customTargetNames"
- v-model:targetSets="targetSets" :default-unit-system="defaultUnitSystem"/>
- </div>
- <div>
- Target Name Customization:
- <select v-model="options.customTargetNames" aria-label="Target name customization">
- <option :value="false">Disabled</option>
- <option :value="true">Enabled</option>
- </select>
- </div>
- <race-options-input v-model="options"/>
+ <advanced-options-input v-model:defaultUnitSystem="defaultUnitSystem"
+ v-model:options="options" v-model:targetSets="targetSets" :type="Calculators.Workout"/>
</details>
<h2>Workout Splits</h2>
@@ -41,18 +22,17 @@
</template>
<script setup lang="ts">
-import { calculateWorkoutResults } from '@/utils/calculators';
+import { Calculators, calculateWorkoutResults } from '@/utils/calculators';
import type { WorkoutOptions } from '@/utils/calculators';
import { RacePredictionModel } from '@/utils/races';
-import { TargetSetTypes, defaultTargetSets } from '@/utils/targets';
+import { defaultTargetSets } from '@/utils/targets';
import type { WorkoutTarget, WorkoutTargetSet, WorkoutTargetSets } from '@/utils/targets';
import { DistanceUnits, UnitSystems, detectDefaultUnitSystem } from '@/utils/units';
import type { DistanceTime } from '@/utils/units';
+import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
import PaceInput from '@/components/PaceInput.vue';
-import RaceOptionsInput from '@/components/RaceOptionsInput.vue';
import SingleOutputTable from '@/components/SingleOutputTable.vue';
-import TargetSetSelector from '@/components/TargetSetSelector.vue';
import useStorage from '@/composables/useStorage';
diff --git a/tests/unit/components/AdvancedOptionsInput.spec.js b/tests/unit/components/AdvancedOptionsInput.spec.js
@@ -0,0 +1,292 @@
+import { test, expect } from 'vitest';
+import { shallowMount } from '@vue/test-utils';
+import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
+
+test('should be correctly render pace options according to props', () => {
+ // Initialize component
+ const wrapper = shallowMount(AdvancedOptionsInput, {
+ propsData: {
+ defaultUnitSystem: 'metric',
+ options: {
+ selectedTargetSet: 'B',
+ },
+ targetSets: {
+ 'A': {
+ name: '1st target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
+ ],
+ },
+ 'B': {
+ name: '2nd target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
+ ],
+ },
+ },
+ type: 'pace',
+ },
+ });
+
+ // Assert all input fields are correct
+ expect(wrapper.find('select[aria-label="Default units"]').element.value).to.equal('metric');
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
+ .equal('B');
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.targetSets).to.deep.equal({
+ 'A': {
+ name: '1st target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
+ ],
+ },
+ 'B': {
+ name: '2nd target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
+ ],
+ },
+ });
+ expect(wrapper.findAll('select[aria-label="Target name customization"]')).to.have
+ .length(0);
+ expect(wrapper.findAll('select[aria-label="Prediction model"]')).to.have.length(0);
+ expect(wrapper.findAllComponents({ name: 'decimal-input' })).to.have.length(0);
+});
+
+test('should be correctly render race options according to props', () => {
+ // Initialize component
+ const wrapper = shallowMount(AdvancedOptionsInput, {
+ propsData: {
+ defaultUnitSystem: 'metric',
+ options: {
+ model: 'PurdyPointsModel',
+ riegelExponent: 1.2,
+ selectedTargetSet: '_new',
+ },
+ type: 'race',
+ targetSets: {},
+ },
+ });
+
+ // Assert input fields are correct
+ expect(wrapper.find('select[aria-label="Default units"]').element.value).to
+ .equal('metric');
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
+ .equal('_new');
+ expect(wrapper.findAll('select[aria-label="Target name customization"]')).to.have
+ .length(0);
+ 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);
+});
+
+test('should be correctly render split options according to props', () => {
+ // Initialize component
+ const wrapper = shallowMount(AdvancedOptionsInput, {
+ propsData: {
+ defaultUnitSystem: 'metric',
+ options: {
+ selectedTargetSet: '_new',
+ },
+ targetSets: {},
+ type: 'split',
+ },
+ });
+
+ // Assert input fields are correct
+ expect(wrapper.find('select[aria-label="Default units"]').element.value).to
+ .equal('metric');
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
+ .equal('_new');
+ expect(wrapper.findAll('select[aria-label="Target name customization"]')).to.have
+ .length(0);
+ expect(wrapper.findAll('select[aria-label="Prediction model"]')).to.have.length(0);
+ expect(wrapper.findAllComponents({ name: 'decimal-input' })).to.have.length(0);
+});
+
+test('should be correctly render workout options according to props', () => {
+ // Initialize component
+ const wrapper = shallowMount(AdvancedOptionsInput, {
+ propsData: {
+ defaultUnitSystem: 'metric',
+ options: {
+ customTargetNames: true,
+ model: 'PurdyPointsModel',
+ riegelExponent: 1.2,
+ selectedTargetSet: '_new',
+ },
+ targetSets: {},
+ type: 'workout',
+ },
+ });
+
+ // Assert input fields are correct
+ expect(wrapper.find('select[aria-label="Default units"]').element.value).to.equal('metric');
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
+ .equal('_new');
+ expect(wrapper.find('select[aria-label="Target name customization"]').element.value).to
+ .equal('true');
+ 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);
+});
+
+test('should pass correct props to TargetSetSelector', async () => {
+ // Initialize component
+ const wrapper = shallowMount(AdvancedOptionsInput, {
+ propsData: {
+ defaultUnitSystem: 'metric',
+ options: {
+ customTargetNames: false,
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: 'B',
+ },
+ targetSets: {
+ 'A': {
+ name: '1st target set v2',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
+ ],
+ },
+ 'B': {
+ name: '2nd target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
+ ],
+ },
+ },
+ type: 'workout',
+ },
+ });
+
+ // Assert props are correct
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('B');
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.targetSets).to.deep.equal({
+ 'A': {
+ name: '1st target set v2',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
+ ],
+ },
+ 'B': {
+ name: '2nd target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
+ ],
+ },
+ });
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.customWorkoutNames)
+ .to.equal(false);
+
+ // Update options
+ await wrapper.find('select[aria-label="Target name customization"]').setValue('true');
+
+ // Assert props are updated
+ expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.customWorkoutNames)
+ .to.equal(true);
+});
+
+test('should emit input events when options are modified', async () => {
+ // Initialize component
+ const wrapper = shallowMount(AdvancedOptionsInput, {
+ propsData: {
+ defaultUnitSystem: 'metric',
+ options: {
+ customTargetNames: false,
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: '_new',
+ },
+ targetSets: {},
+ type: 'workout',
+ },
+ });
+
+ // Update options
+ await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'target-set-selector' }).setValue({
+ 'A': {
+ name: '1st target set v2',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
+ ],
+ },
+ 'B': {
+ name: '2nd target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
+ ],
+ },
+ }, 'targetSets');
+ await wrapper.findComponent({ name: 'target-set-selector' }).setValue('B', 'selectedTargetSet');
+ await wrapper.find('select[aria-label="Target name customization"]').setValue('true');
+ await wrapper.find('select[aria-label="Prediction model"]').setValue('CameronModel');
+ await wrapper.findComponent({ name: 'decimal-input' }).setValue(1.3);
+
+ // Assert correct update events emitted
+ expect(wrapper.emitted()['update:defaultUnitSystem']).to.deep.equal([['imperial']]);
+ expect(wrapper.emitted()['update:targetSets']).to.deep.equal([[{
+ 'A': {
+ name: '1st target set v2',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
+ { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
+ ],
+ },
+ 'B': {
+ name: '2nd target set',
+ targets: [
+ { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
+ { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
+ ],
+ },
+ }]]);
+ expect(wrapper.emitted()['update:options']).to.deep.equal([
+ [{
+ customTargetNames: false,
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: 'B',
+ }],
+ [{
+ customTargetNames: true,
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: 'B',
+ }],
+ [{
+ customTargetNames: true,
+ model: 'CameronModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: 'B',
+ }],
+ [{
+ customTargetNames: true,
+ model: 'CameronModel',
+ riegelExponent: 1.3,
+ selectedTargetSet: 'B',
+ }],
+ ]);
+});
diff --git a/tests/unit/views/BatchCalculator.spec.js b/tests/unit/views/BatchCalculator.spec.js
@@ -104,8 +104,7 @@ test('should load default units setting from localStorage', async () => {
const wrapper = shallowMount(BatchCalculator);
// Assert default units setting loaded
- expect(wrapper.find('select[aria-label="Default units"]').element.value).to.equal('metric');
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.defaultUnitSystem)
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.defaultUnitSystem)
.to.equal('metric');
});
@@ -117,7 +116,8 @@ test('should save default units setting from localStorage when modified', async
const wrapper = shallowMount(BatchCalculator);
// Change default units setting
- await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// New default units should be saved to localStorage
expect(localStorage.getItem('running-tools.default-unit-system')).to.equal('"imperial"');
@@ -195,32 +195,30 @@ test('should load calculator options from localStorage', async () => {
// Assert pace calculator options are loaded
await wrapper.find('select[aria-label="Calculator"]').setValue('pace');
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('A');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
+ selectedTargetSet: 'A',
+ });
expect(wrapper.findComponent({ name: 'double-output-table' }).vm.targets)
.to.deep.equal(selectedTargetSets[0].targets);
// Assert race calculator options are loaded
await wrapper.find('select[aria-label="Calculator"]').setValue('race');
- expect(wrapper.findComponent({ name: 'RaceOptionsInput' }).vm.modelValue).to.deep.equal({
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
model: 'PurdyPointsModel',
riegelExponent: 1.2,
selectedTargetSet: 'C',
});
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('C');
expect(wrapper.findComponent({ name: 'double-output-table' }).vm.targets)
.to.deep.equal(selectedTargetSets[1].targets);
// Assert workout calculator options are loaded
await wrapper.find('select[aria-label="Calculator"]').setValue('workout');
- expect(wrapper.findComponent({ name: 'RaceOptionsInput' }).vm.modelValue).to.deep.equal({
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
customTargetNames: true,
model: 'RiegelModel',
riegelExponent: 1.1,
selectedTargetSet: 'E',
});
- expect(wrapper.find('select[aria-label="Target name customization"]').element.value)
- .to.equal('true');
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('E');
expect(wrapper.findComponent({ name: 'double-output-table' }).vm.targets)
.to.deep.equal(selectedTargetSets[2].targets);
});
@@ -297,31 +295,30 @@ test('should save calculator options to localStorage when modified', async () =>
// Update pace calculator options X
await wrapper.find('select[aria-label="Calculator"]').setValue('pace');
- await wrapper.findComponent({ name: 'target-set-selector' }).setValue('A', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ selectedTargetSet: 'A',
+ }, 'options');
expect(wrapper.findComponent({ name: 'double-output-table' }).vm.targets)
.to.deep.equal(selectedTargetSets[0].targets);
// Update race calculator options
await wrapper.find('select[aria-label="Calculator"]').setValue('race');
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
model: 'PurdyPointsModel',
riegelExponent: 1.2,
- selectedTargetSet: 'D',
- });
- await wrapper.findComponent({ name: 'target-set-selector' }).setValue('C', 'selectedTargetSet');
+ selectedTargetSet: 'C',
+ }, 'options');
expect(wrapper.findComponent({ name: 'double-output-table' }).vm.targets)
.to.deep.equal(selectedTargetSets[1].targets);
// Update workout calculator options
await wrapper.find('select[aria-label="Calculator"]').setValue('workout');
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
- customTargetNames: false,
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ customTargetNames: true,
model: 'RiegelModel',
riegelExponent: 1.1,
- selectedTargetSet: 'F',
- });
- wrapper.find('select[aria-label="Target name customization"]').setValue('true');
- await wrapper.findComponent({ name: 'target-set-selector' }).setValue('E', 'selectedTargetSet');
+ selectedTargetSet: 'E',
+ }, 'options');
expect(wrapper.findComponent({ name: 'double-output-table' }).vm.targets)
.to.deep.equal(selectedTargetSets[2].targets);
@@ -399,6 +396,23 @@ test('should pass correct input props to DoubleOutputTable', async () => {
]);
});
+test('should correctly set AdvancedOptionsInput type prop', async () => {
+ // Initialize component
+ const wrapper = shallowMount(BatchCalculator);
+
+ // Assert prop is correct for pace calculator
+ await wrapper.find('select[aria-label="Calculator"]').setValue('pace');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.type).to.equal('pace');
+
+ // Update race calculator options
+ await wrapper.find('select[aria-label="Calculator"]').setValue('race');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.type).to.equal('race');
+
+ // Update workout calculator options
+ await wrapper.find('select[aria-label="Calculator"]').setValue('workout');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.type).to.equal('workout');
+});
+
test('should correctly calculate outputs', async () => {
// Initialize localStorage
localStorage.setItem('running-tools.race-calculator-options', JSON.stringify({
diff --git a/tests/unit/views/PaceCalculator.spec.js b/tests/unit/views/PaceCalculator.spec.js
@@ -48,7 +48,8 @@ test('should correctly calculate distance results according to default units set
});
// Set default units
- await wrapper.find('select[aria-label="Default units"]').setValue('metric');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('metric', 'defaultUnitSystem');
// Get calculate result function
const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult;
@@ -58,7 +59,8 @@ test('should correctly calculate distance results according to default units set
expect(result.key).to.equal('1.61 km');
// Change default units
- await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// Assert result is correct
result = calculateResult({ type: 'time', time: 600 });
@@ -78,15 +80,15 @@ test('should correctly handle null target set', async () => {
const wrapper = shallowMount(PaceCalculator);
// Switch to invalid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('does_not_exist', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue({ selectedTargetSet: 'does_not_exist' }, 'options');
// Assert empty array passed to SingleOutputTable component
expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets).to.deep.equal([]);
// Switch to valid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('_pace_targets', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue({ selectedTargetSet: '_pace_targets' }, 'options');
// Assert valid targets passed to SingleOutputTable component
const paceTargets = defaultTargetSets._pace_targets.targets;
@@ -161,8 +163,8 @@ test('should load options from localStorage', async () => {
const wrapper = shallowMount(PaceCalculator);
// Assert selection is loaded
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
- .to.equal('B');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options)
+ .to.deep.equal({ selectedTargetSet: 'B' });
expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets)
.to.deep.equal(targetSet2.targets);
});
@@ -172,8 +174,8 @@ test('should save options to localStorage when modified', async () => {
const wrapper = shallowMount(PaceCalculator);
// Select a new target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('B', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue({ selectedTargetSet: 'B' }, 'options');
// New selected target set should be saved to localStorage
expect(localStorage.getItem('running-tools.pace-calculator-options')).to.equal(JSON.stringify({
@@ -186,8 +188,10 @@ test('should save default units setting to localStorage when modified', async ()
const wrapper = shallowMount(PaceCalculator);
// Change default units
- await wrapper.find('select[aria-label="Default units"]').setValue('metric');
- await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('metric', 'defaultUnitSystem');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// New default units should be saved to localStorage
expect(localStorage.getItem('running-tools.default-unit-system')).to.equal('"imperial"');
diff --git a/tests/unit/views/RaceCalculator.spec.js b/tests/unit/views/RaceCalculator.spec.js
@@ -46,7 +46,8 @@ test('should correctly calculate distance results according to default units set
});
// Set default units
- await wrapper.find('select[aria-label="Default units"]').setValue('metric');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('metric', 'defaultUnitSystem');
// Get calculate result function
const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult;
@@ -60,7 +61,8 @@ test('should correctly calculate distance results according to default units set
expect(result.sort).to.equal(2495);
// Change default units
- await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// Assert result is correct
result = calculateResult({ type: 'time', time: 2495 });
@@ -84,15 +86,21 @@ test('should correctly handle null target set', async () => {
const wrapper = shallowMount(RaceCalculator);
// Switch to invalid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('does_not_exist', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: 'does_not_exist',
+ }, 'options');
// Assert empty array passed to SingleOutputTable component
expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets).to.deep.equal([]);
// Switch to valid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('_race_targets', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: '_race_targets',
+ }, 'options');
// Assert valid targets passed to SingleOutputTable component
const raceTargets = defaultTargetSets._race_targets.targets;
@@ -135,11 +143,11 @@ test('should correctly calculate results according to model options', async () =
});
// Switch model
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
- model: 'RiegelModel',
- riegelExponent: 1.06, // default value
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ model: 'RiegelModel', // changed from the Riegel Model
+ riegelExponent: 1.06,
selectedTargetSet: '_race_targets',
- });
+ }, 'options');
// Calculate result
const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult;
@@ -153,11 +161,11 @@ test('should correctly calculate results according to model options', async () =
expect(result.value).to.equal('41:41.92');
// Update Riegel Exponent
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
- model: 'RiegelModel', // existing value
- riegelExponent: 1,
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ model: 'RiegelModel',
+ riegelExponent: 1, // changed from 1.06
selectedTargetSet: '_race_targets',
- });
+ }, 'options');
// Calculate result
result = calculateResult({
@@ -213,8 +221,10 @@ test('should save default units setting to localStorage when modified', async ()
const wrapper = shallowMount(RaceCalculator);
// Change default units
- await wrapper.find('select[aria-label="Default units"]').setValue('metric');
- await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('metric', 'defaultUnitSystem');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// New default units should be saved to localStorage
expect(localStorage.getItem('running-tools.default-unit-system')).to.equal('"imperial"');
@@ -251,13 +261,11 @@ test('should load options from localStorage', async () => {
const wrapper = shallowMount(RaceCalculator);
// Assert data loaded
- expect(wrapper.findComponent({ name: 'RaceOptionsInput' }).vm.modelValue).to.deep.equal({
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
model: 'PurdyPointsModel',
riegelExponent: 1.2,
selectedTargetSet: 'B',
});
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
- .to.equal('B');
expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets)
.to.deep.equal(targetSet2.targets);
});
@@ -267,13 +275,11 @@ test('should save options to localStorage when modified', async () => {
const wrapper = shallowMount(RaceCalculator);
// Update options
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
model: 'CameronModel',
riegelExponent: 1.30,
- selectedTargetSet: '_race_targets',
- });
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('B', 'selectedTargetSet');
+ selectedTargetSet: 'B',
+ }, 'options');
// Assert data saved to localStorage
expect(localStorage.getItem('running-tools.race-calculator-options')).to.equal(JSON.stringify({
@@ -282,4 +288,3 @@ test('should save options to localStorage when modified', async () => {
selectedTargetSet: 'B',
}));
});
-
diff --git a/tests/unit/views/SplitCalculator.spec.js b/tests/unit/views/SplitCalculator.spec.js
@@ -16,7 +16,9 @@ test('should load selected target set from localStorage', async () => {
const wrapper = shallowMount(SplitCalculator);
// Assert selection is loaded
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('B');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
+ selectedTargetSet: 'B',
+ });
});
test('should load targets from localStorage and pass to splitOutputTable', async () => {
@@ -44,8 +46,9 @@ test('should load targets from localStorage and pass to splitOutputTable', async
const wrapper = shallowMount(SplitCalculator);
// Assert default split targets are initially loaded
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
- .to.equal('_split_targets');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
+ selectedTargetSet: '_split_targets',
+ });
expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue).to.deep.equal([
{ type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
{ type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
@@ -53,11 +56,11 @@ test('should load targets from localStorage and pass to splitOutputTable', async
]);
// Select a new target set
- await wrapper.findComponent({ name: 'target-set-selector' }).setValue('B', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ selectedTargetSet: 'B',
+ }, 'options');
// Assert new target set is loaded
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
- .to.equal('B');
expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue).to.deep.equal([
{ type: 'distance', distanceValue: 1, distanceUnit: 'kilometers', split: 180 },
{ type: 'distance', distanceValue: 2, distanceUnit: 'kilometers', split: 190 },
@@ -75,15 +78,17 @@ test('should correctly handle null target set', async () => {
const wrapper = shallowMount(SplitCalculator);
// Assert selection is loaded
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
- .to.equal('does_not_exist');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
+ selectedTargetSet: 'does_not_exist',
+ });
// Assert empty array passed to SplitOutputTable
expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue).to.deep.equal([]);
// Switch to valid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('_split_targets', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ selectedTargetSet: '_split_targets',
+ }, 'options');
// Assert non-empty target set passed to SplitOutputTable
expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue).to.deep.equal([
@@ -134,8 +139,9 @@ test('should save selected target set to localStorage when modified', async () =
const wrapper = shallowMount(SplitCalculator);
// Select a new target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('_race_targets', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ selectedTargetSet: '_race_targets',
+ }, 'options');
// New selected target set should be saved to localStorage
expect(localStorage.getItem('running-tools.split-calculator-options')).to.equal(JSON.stringify({
@@ -151,14 +157,16 @@ test('should load default units from localStorage and pass to splitOutputTable',
const wrapper = shallowMount(SplitCalculator);
// Assert default units setting is initialy loaded
- expect(wrapper.find('select', { name: 'Default units' }).element.value).to.equal('metric');
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.defaultUnitSystem)
+ .to.equal('metric');
// Assert prop is correct
expect(wrapper.findComponent({ name: 'split-output-table' }).vm.defaultUnitSystem)
.to.equal('metric');
// Change default units
- await wrapper.find('select').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// Assert prop is correct
expect(wrapper.findComponent({ name: 'split-output-table' }).vm.defaultUnitSystem)
@@ -170,22 +178,24 @@ test('should save default units setting to localStorage when modified', async ()
const wrapper = shallowMount(SplitCalculator);
// Set default units setting
- await wrapper.find('select').setValue('metric');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('metric', 'defaultUnitSystem');
// New default units should be saved to localStorage
expect(localStorage.getItem('running-tools.default-unit-system')).to.equal('"metric"');
// Set default units setting
- await wrapper.find('select').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// New default units should be saved to localStorage
expect(localStorage.getItem('running-tools.default-unit-system')).to.equal('"imperial"');
});
-test('should correctly set targetSetSelector setType prop', async () => {
+test('should correctly set AdvancedOptionsInput type prop', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- // Assert setType prop is correctly set
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.setType).to.equal('split');
+ // Assert type prop is correctly set
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.type).to.equal('split');
});
diff --git a/tests/unit/views/WorkoutCalculator.spec.js b/tests/unit/views/WorkoutCalculator.spec.js
@@ -37,15 +37,23 @@ test('should correctly handle null target set', async () => {
const wrapper = shallowMount(WorkoutCalculator);
// Switch to invalid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('does_not_exist', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ customTargetNames: false,
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: 'does_not_exist',
+ }, 'options');
// Assert empty array passed to SingleOutputTable component
expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets).to.deep.equal([]);
// Switch to valid target set
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('_workout_targets', 'selectedTargetSet');
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ customTargetNames: false,
+ model: 'AverageModel',
+ riegelExponent: 1.06,
+ selectedTargetSet: '_workout_targets',
+ }, 'options');
// Assert valid targets passed to SingleOutputTable component
const workoutTargets = defaultTargetSets._workout_targets.targets;
@@ -65,11 +73,12 @@ test('should correctly calculate results according to advanced model options', a
});
// Update model and Riegel Exponent
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ customTargetNames: false,
model: 'RiegelModel',
riegelExponent: 1.10,
selectedTargetSet: '_workout_targets',
- });
+ }, 'options');
// Calculate result
const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult;
@@ -127,8 +136,10 @@ test('should save default units setting to localStorage when modified', async ()
const wrapper = shallowMount(WorkoutCalculator);
// Change default units
- await wrapper.find('select[aria-label="Default units"]').setValue('metric');
- await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('metric', 'defaultUnitSystem');
+ await wrapper.findComponent({ name: 'advanced-options-input' })
+ .setValue('imperial', 'defaultUnitSystem');
// New default units should be saved to localStorage
expect(localStorage.getItem('running-tools.default-unit-system')).to.equal('"imperial"');
@@ -191,18 +202,14 @@ test('should load options from localStorage', async () => {
const wrapper = shallowMount(WorkoutCalculator);
// Assert data loaded
- expect(wrapper.findComponent({ name: 'RaceOptionsInput' }).vm.modelValue).to.deep.equal({
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({
customTargetNames: true,
model: 'PurdyPointsModel',
riegelExponent: 1.2,
selectedTargetSet: 'B',
});
- expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
- .to.equal('B');
expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets)
.to.deep.equal(targetSet2.targets);
- expect(wrapper.find('select[aria-label="Target name customization"]').element.value)
- .to.equal('true');
});
test('should save options to localStorage when modified', async () => {
@@ -210,15 +217,12 @@ test('should save options to localStorage when modified', async () => {
const wrapper = shallowMount(WorkoutCalculator);
// Update options
- await wrapper.findComponent({ name: 'RaceOptionsInput' }).setValue({
- customTargetNames: false,
+ await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({
+ customTargetNames: true,
model: 'CameronModel',
- riegelExponent: 1.30,
- selectedTargetSet: '_workout_targets',
- });
- wrapper.find('select[aria-label="Target name customization"]').setValue('true');
- await wrapper.findComponent({ name: 'target-set-selector' })
- .setValue('B', 'selectedTargetSet');
+ riegelExponent: 1.3,
+ selectedTargetSet: 'B',
+ }, 'options');
// Assert data saved to localStorage
expect(localStorage.getItem('running-tools.workout-calculator-options')).to.equal(JSON.stringify({
@@ -228,3 +232,11 @@ test('should save options to localStorage when modified', async () => {
selectedTargetSet: 'B',
}));
});
+
+test('should correctly set AdvancedOptionsInput type prop', async () => {
+ // Initialize component
+ const wrapper = shallowMount(WorkoutCalculator);
+
+ // Assert type prop is correctly set
+ expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.type).to.equal('workout');
+});