commit baf7d0840cf02ec30ba13068dc64deb4c28969d9
parent b490ff7f0e90684a1eb94726ed8396527797e16f
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date: Mon, 27 May 2024 11:08:42 -0700
Implement useStorage composable
Diffstat:
12 files changed, 142 insertions(+), 398 deletions(-)
diff --git a/src/components/TargetSetSelector.vue b/src/components/TargetSetSelector.vue
@@ -21,11 +21,10 @@
</template>
<script setup>
-import { nextTick, onActivated, ref, watch } from 'vue';
+import { nextTick, ref, watch } from 'vue';
import VueFeather from 'vue-feather';
-import storage from '@/utils/localStorage';
import targetUtils from '@/utils/targets';
import TargetEditor from '@/components/TargetEditor.vue';
diff --git a/src/composables/useStorage.js b/src/composables/useStorage.js
@@ -0,0 +1,36 @@
+import { ref, onActivated, watchEffect } from 'vue';
+
+// The global localStorage prefix
+const prefix = 'running-tools';
+
+/*
+ * Create a reactive value that is synced with a localStorage item
+ * @param {String} key The localStorage item's key
+ * @defaultValue {Object} defaultValue The default value
+ */
+export default function useStorage(key, defaultValue) {
+ const clonedDefault = JSON.parse(JSON.stringify(defaultValue));
+ const value = ref(clonedDefault);
+
+ // (Re)load value from localStorage
+ function updateValue() {
+ let parsedValue;
+ try {
+ parsedValue = JSON.parse(localStorage.getItem(`${prefix}.${key}`));
+ } catch {
+ parsedValue = null;
+ }
+ if (parsedValue !== null) value.value = parsedValue;
+ }
+ updateValue();
+ onActivated(updateValue);
+
+ // Save value to localStorage when modified
+ watchEffect(() => {
+ if (typeof localStorage !== 'undefined') {
+ localStorage.setItem(`${prefix}.${key}`, JSON.stringify(value.value));
+ }
+ })
+
+ return value
+}
diff --git a/src/utils/localStorage.js b/src/utils/localStorage.js
@@ -1,40 +0,0 @@
-// The global localStorage prefix
-const prefix = 'running-tools';
-
-/**
- * Get the value of a key from localStorage
- * @param {String} key The key
- * @param {Object} defaultValue The default value
- * @returns {Object} The value
- */
-function get(key, defaultValue) {
- // Clone defaultValue
- const clonedDefault = JSON.parse(JSON.stringify(defaultValue));
-
- if (key === null) {
- return clonedDefault;
- }
- let value;
- try {
- value = JSON.parse(localStorage.getItem(`${prefix}.${key}`));
- } catch {
- return clonedDefault;
- }
- return value === null ? clonedDefault : value;
-}
-
-/**
- * Set the value of a key in localStorage
- * @param {String} key The key
- * @param {Object} value The value
- * */
-function set(key, value) {
- if (typeof localStorage !== 'undefined') {
- localStorage.setItem(`${prefix}.${key}`, JSON.stringify(value));
- }
-}
-
-export default {
- get,
- set,
-};
diff --git a/src/views/PaceCalculator.vue b/src/views/PaceCalculator.vue
@@ -43,10 +43,9 @@
</template>
<script setup>
-import { computed, onActivated, ref, watch } from 'vue';
+import { computed } from 'vue';
import paceUtils from '@/utils/paces';
-import storage from '@/utils/localStorage';
import targetUtils from '@/utils/targets';
import unitUtils from '@/utils/units';
@@ -55,81 +54,37 @@ import SimpleTargetTable from '@/components/SimpleTargetTable.vue';
import TargetSetSelector from '@/components/TargetSetSelector.vue';
import TimeInput from '@/components/TimeInput.vue';
+import useStorage from '@/composables/useStorage';
+
/**
* The input distance value
*/
-const inputDistance = ref(storage.get('pace-calculator-input-distance', 5));
+const inputDistance = useStorage('pace-calculator-input-distance', 5);
/**
* The input distance unit
*/
-const inputUnit = ref(storage.get('pace-calculator-input-unit', 'kilometers'));
+const inputUnit = useStorage('pace-calculator-input-unit', 'kilometers');
/**
* The input time value
*/
-const inputTime = ref(storage.get('pace-calculator-input-time', 20 * 60));
+const inputTime = useStorage('pace-calculator-input-time', 20 * 60);
/**
* The default unit system
- *
- * Loaded in onActivated() hook
*/
-const defaultUnitSystem = ref(null);
+const defaultUnitSystem = useStorage('default-unit-system', unitUtils.detectDefaultUnitSystem());
/**
* The current selected target set
*/
-const selectedTargetSet = ref(storage.get('pace-calculator-target-set', '_pace_targets'));
+const selectedTargetSet = useStorage('pace-calculator-target-set', '_pace_targets');
/**
* The target sets
- *
- * Loaded in onActivated() hook
- */
-const targetSets = ref({});
-
-/**
- * Save input distance value
- */
-watch(inputDistance, (newValue) => {
- storage.set('pace-calculator-input-distance', newValue);
-});
-
-/**
- * Save input distance unit
- */
-watch(inputUnit, (newValue) => {
- storage.set('pace-calculator-input-unit', newValue);
-});
-
-/**
- * Save input time value
- */
-watch(inputTime, (newValue) => {
- storage.set('pace-calculator-input-time', newValue);
-});
-
-/**
- * Save default unit system
*/
-watch(defaultUnitSystem, (newValue) => {
- storage.set('default-unit-system', newValue);
-});
-
-/**
- * Save the current selected target set
- */
-watch(selectedTargetSet, (newValue) => {
- storage.set('pace-calculator-target-set', newValue);
-});
-
-/**
- * Save target sets
- */
-watch(targetSets, (newValue) => {
- storage.set('target-sets', newValue);
-}, { deep: true });
+const targetSets = useStorage('target-sets', targetUtils.defaultTargetSets);
/**
* The input pace (in seconds per meter)
@@ -140,13 +95,6 @@ const pace = computed(() => {
});
/**
- * Reload the target sets
- */
-function reloadTargets() {
- targetSets.value = storage.get('target-sets', targetUtils.defaultTargetSets);
-}
-
-/**
* Calculate paces from a target
* @param {Object} target The target
* @returns {Object} The result
@@ -186,14 +134,6 @@ function calculatePace(target) {
// Return result
return result;
}
-
-/**
- * (Re)load settings used in multiple calculators
- */
-onActivated(() => {
- reloadTargets();
- defaultUnitSystem.value = storage.get('default-unit-system', unitUtils.detectDefaultUnitSystem());
-});
</script>
<style scoped>
diff --git a/src/views/RaceCalculator.vue b/src/views/RaceCalculator.vue
@@ -74,11 +74,10 @@
</template>
<script setup>
-import { computed, onActivated, ref, watch } from 'vue';
+import { computed } from 'vue';
import formatUtils from '@/utils/format';
import raceUtils from '@/utils/races';
-import storage from '@/utils/localStorage';
import targetUtils from '@/utils/targets';
import unitUtils from '@/utils/units';
@@ -87,56 +86,47 @@ import SimpleTargetTable from '@/components/SimpleTargetTable.vue';
import TargetSetSelector from '@/components/TargetSetSelector.vue';
import TimeInput from '@/components/TimeInput.vue';
+import useStorage from '@/composables/useStorage';
+
/**
* The input distance value
*/
-const inputDistance = ref(storage.get('race-calculator-input-distance', 5));
+const inputDistance = useStorage('race-calculator-input-distance', 5);
/**
* The input distance unit
*/
-const inputUnit = ref(storage.get('race-calculator-input-unit', 'kilometers'));
+const inputUnit = useStorage('race-calculator-input-unit', 'kilometers');
/**
* The input time value
*/
-const inputTime = ref(storage.get('race-calculator-input-time', 20 * 60));
+const inputTime = useStorage('race-calculator-input-time', 20 * 60);
/**
* The default unit system
- *
- * Loaded in onActivated() hook
*/
-const defaultUnitSystem = ref(null);
+const defaultUnitSystem = useStorage('default-unit-system', unitUtils.detectDefaultUnitSystem());
/**
* The race prediction model
*/
-const model = ref(storage.get('race-calculator-model', 'AverageModel'));
+const model = useStorage('race-calculator-model', 'AverageModel');
/**
* The value of the exponent in Riegel's Model
*/
-const riegelExponent = ref(storage.get('race-calculator-riegel-exponent', 1.06));
+const riegelExponent = useStorage('race-calculator-riegel-exponent', 1.06);
/**
* The current selected target set
*/
-const selectedTargetSet = ref(storage.get('race-calculator-target-set', '_race_targets'));
+const selectedTargetSet = useStorage('race-calculator-target-set', '_race_targets');
/**
* The target sets
- *
- * Loaded in onActivated() hook
*/
-let targetSets = ref({});
-
-/**
- * Reload the target sets
- */
-function reloadTargets() {
- targetSets.value = storage.get('target-sets', targetUtils.defaultTargetSets);
-}
+let targetSets = useStorage('target-sets', targetUtils.defaultTargetSets);
/**
* Predict race results from a target
@@ -258,70 +248,6 @@ const vo2Percentage = computed(() => {
const result = raceUtils.VO2MaxModel.getVO2Percentage(inputTime.value) * 100;
return result;
});
-
-/**
- * Save input distance value
- */
-watch(inputDistance, (newValue) => {
- storage.set('race-calculator-input-distance', newValue);
-});
-
-/**
- * Save input distance unit
- */
-watch(inputUnit, (newValue) => {
- storage.set('race-calculator-input-unit', newValue);
-});
-
-/**
- * Save input time value
- */
-watch(inputTime, (newValue) => {
- storage.set('race-calculator-input-time', newValue);
-});
-
-/**
- * Save default unit system
- */
-watch(defaultUnitSystem, (newValue) => {
- storage.set('default-unit-system', newValue);
-});
-
-/**
- * Save prediction model
- */
-watch(model, (newValue) => {
- storage.set('race-calculator-model', newValue);
-});
-
-/**
- * Save Riegel Model exponent
- */
-watch(riegelExponent, (newValue) => {
- storage.set('race-calculator-riegel-exponent', newValue);
-});
-
-/**
- * Save the current selected target set
- */
-watch(selectedTargetSet, (newValue) => {
- storage.set('race-calculator-target-set', newValue);
-});
-
-/**
- * Save target sets
- */
-watch(targetSets, (newValue) => {
- storage.set('target-sets', newValue);
-}, { deep: true });
-
-/**
-* (Re)load settings used in multiple calculators
-*/
-onActivated(() => {
- reloadTargets();
- defaultUnitSystem.value = storage.get('default-unit-system', unitUtils.detectDefaultUnitSystem());
-});
</script>
<style scoped>
diff --git a/src/views/SplitCalculator.vue b/src/views/SplitCalculator.vue
@@ -66,55 +66,31 @@
</template>
<script setup>
-import { computed, onActivated, ref, watch } from 'vue';
+import { computed } from 'vue';
import formatUtils from '@/utils/format';
-import storage from '@/utils/localStorage';
import targetUtils from '@/utils/targets';
import unitUtils from '@/utils/units';
import TargetSetSelector from '@/components/TargetSetSelector.vue';
import TimeInput from '@/components/TimeInput.vue';
+import useStorage from '@/composables/useStorage';
+
/**
* The default unit system
- *
- * Loaded in onActivated() hook
*/
-const defaultUnitSystem = ref(null);
+const defaultUnitSystem = useStorage('default-unit-system', unitUtils.detectDefaultUnitSystem());
/**
* The current selected target set
*/
-const selectedTargetSet = ref(storage.get('split-calculator-target-set', '_split_targets'));
+const selectedTargetSet = useStorage('split-calculator-target-set', '_split_targets');
/**
* The default output targets
- *
- * Loaded in onActivated() hook
- */
-const targetSets = ref({});
-
-/**
- * Save default unit system
- */
-watch(defaultUnitSystem, (newValue) => {
- storage.set('default-unit-system', newValue);
-});
-
-/**
- * Save the current selected target set
- */
-watch(selectedTargetSet, (newValue) => {
- storage.set('split-calculator-target-set', newValue);
-});
-
-/**
- * Save target sets
*/
-watch(targetSets, (newValue) => {
- storage.set('target-sets', newValue);
-}, { deep: true });
+const targetSets = useStorage('target-sets', targetUtils.defaultTargetSets);
/**
* The target table results
@@ -159,21 +135,6 @@ const results = computed(() => {
// Return results array
return results;
});
-
-/**
- * Reload the target sets
- */
-function reloadTargets() {
- targetSets.value = storage.get('target-sets', targetUtils.defaultTargetSets);
-}
-
-/**
- * (Re)load settings used in multiple calculators
- */
-onActivated(() => {
- reloadTargets();
- defaultUnitSystem.value = storage.get('default-unit-system', unitUtils.detectDefaultUnitSystem());
-});
</script>
<style scoped>
diff --git a/src/views/UnitCalculator.vue b/src/views/UnitCalculator.vue
@@ -6,12 +6,12 @@
<option value="speed_and_pace">Speed & Pace</option>
</select>
- <time-input v-if="getUnitType(inputUnit) === 'time'" class="input-value"
- label="Input time" v-model="inputValue"/>
+ <time-input v-if="getUnitType(input.inputUnit) === 'time'" class="input-value"
+ label="Input time" v-model="input.inputValue"/>
<decimal-input v-else class="input-value" aria-label="Input value"
- v-model="inputValue" :min="0" :digits="2"/>
+ v-model="input.inputValue" :min="0" :digits="2"/>
- <select v-model="inputUnit" class="input-units" aria-label="Input units">
+ <select v-model="input.inputUnit" class="input-units" aria-label="Input units">
<option v-for="(value, key) in units" :key="key" :value="key">
{{ value.name }}
</option>
@@ -19,14 +19,14 @@
<span class="equals"> = </span>
- <span v-if="getUnitType(outputUnit) === 'time'" class="output-value" aria-label="Output value">
+ <span v-if="getUnitType(input.outputUnit) === 'time'" class="output-value" aria-label="Output value">
{{ formatUtils.formatDuration(outputValue, 6, 3, true) }}
</span>
<span v-else class="output-value" aria-label="Output value">
{{ formatUtils.formatNumber(outputValue, 0, 3, true) }}
</span>
- <select v-model="outputUnit" class="output-units" aria-label="Output units">
+ <select v-model="input.outputUnit" class="output-units" aria-label="Output units">
<option v-for="(value, key) in units" :key="key" :value="key">
{{ value.name }}
</option>
@@ -35,34 +35,53 @@
</template>
<script setup>
- import { computed, ref, watch } from 'vue';
+import { computed, ref } from 'vue';
import formatUtils from '@/utils/format';
-import storage from '@/utils/localStorage';
import unitUtils from '@/utils/units';
import DecimalInput from '@/components/DecimalInput.vue';
import TimeInput from '@/components/TimeInput.vue';
-/**
- * The input value
- */
-const inputValue = ref(storage.get('unit-calculator-distance-input-value', 1.0));
+import useStorage from '@/composables/useStorage';
/**
- * The unit of the input
+ * The calculator inputs
*/
-const inputUnit = ref(storage.get('unit-calculator-distance-input-unit', 'miles'));
+const inputs = useStorage('unit-calculator-inputs', {
+ distance: {
+ inputValue: 1,
+ inputUnit: 'miles',
+ outputUnit: 'kilometers',
+ },
+ time: {
+ inputValue: 1,
+ inputUnit: 'seconds',
+ outputUnit: 'hh:mm:ss',
+ },
+ speed_and_pace: {
+ inputValue: 600,
+ inputUnit: 'seconds_per_mile',
+ outputUnit: 'miles_per_hour',
+ },
+});
/**
- * The unit of the output
+ * The unit category
*/
-const outputUnit = ref(storage.get('unit-calculator-distance-output-unit', 'kilometers'));
+const category = ref('distance');
/**
- * The unit category
+ * The inputs for the current category
*/
-const category = ref('distance');
+const input = computed({
+ get() {
+ return inputs.value[category.value];
+ },
+ set(newValue) {
+ inputs.value[category.value] = newValue;
+ },
+});
/**
* The names of the units in the current category
@@ -97,18 +116,20 @@ const units = computed(() => {
const outputValue = computed(() => {
switch (category.value) {
case 'distance': {
- return unitUtils.convertDistance(inputValue.value, inputUnit.value, outputUnit.value);
+ return unitUtils.convertDistance(input.value.inputValue, input.value.inputUnit,
+ input.value.outputUnit);
}
case 'time': {
// Correct input and output units for 'hh:mm:ss' unit
- const realInput = inputUnit.value === 'hh:mm:ss' ? 'seconds' : inputUnit.value;
- const realOutput = outputUnit.value === 'hh:mm:ss' ? 'seconds' : outputUnit.value;
+ const realInput = input.value.inputUnit === 'hh:mm:ss' ? 'seconds' : input.value.inputUnit;
+ const realOutput = input.value.outputUnit === 'hh:mm:ss' ? 'seconds' : input.value.outputUnit;
// Calculate conversion
- return unitUtils.convertTime(inputValue.value, realInput, realOutput);
+ return unitUtils.convertTime(input.value.inputValue, realInput, realOutput);
}
case 'speed_and_pace': {
- return unitUtils.convertSpeedPace(inputValue.value, inputUnit.value, outputUnit.value);
+ return unitUtils.convertSpeedPace(input.value.inputValue, input.value.inputUnit,
+ input.value.outputUnit);
}
default: {
return null;
@@ -117,106 +138,6 @@ const outputValue = computed(() => {
});
/**
- * Reset inputValue, inputUnit, and outputUnit
- */
-watch(category, (newValue) => {
- switch (newValue) {
- case 'distance': {
- inputValue.value = storage.get('unit-calculator-distance-input-value', 1);
- inputUnit.value = storage.get('unit-calculator-distance-input-unit', 'miles');
- outputUnit.value = storage.get('unit-calculator-distance-output-unit', 'kilometers');
- break;
- }
- case 'time': {
- inputValue.value = storage.get('unit-calculator-time-input-value', 1);
- inputUnit.value = storage.get('unit-calculator-time-input-unit', 'seconds');
- outputUnit.value = storage.get('unit-calculator-time-output-unit', 'hh:mm:ss');
- break;
- }
- case 'speed_and_pace': {
- inputValue.value = storage.get('unit-calculator-speed-input-value', 600);
- inputUnit.value = storage.get('unit-calculator-speed-input-unit',
- 'seconds_per_mile');
- outputUnit.value = storage.get('unit-calculator-speed-output-unit',
- 'miles_per_hour');
- break;
- }
- default: {
- break;
- }
- }
-});
-
-/**
- * Save input value
- */
-watch(inputValue, (newValue) => {
- switch (category.value) {
- case 'distance': {
- storage.set('unit-calculator-distance-input-value', newValue);
- break;
- }
- case 'time': {
- storage.set('unit-calculator-time-input-value', newValue);
- break;
- }
- case 'speed_and_pace': {
- storage.set('unit-calculator-speed-input-value', newValue);
- break;
- }
- default: {
- break;
- }
- }
-});
-
-/**
- * Save input unit
- */
-watch(inputUnit, (newValue) => {
- switch (category.value) {
- case 'distance': {
- storage.set('unit-calculator-distance-input-unit', newValue);
- break;
- }
- case 'time': {
- storage.set('unit-calculator-time-input-unit', newValue);
- break;
- }
- case 'speed_and_pace': {
- storage.set('unit-calculator-speed-input-unit', newValue);
- break;
- }
- default: {
- break;
- }
- }
-});
-
-/**
- * Save output unit
- */
-watch(outputUnit, (newValue) => {
- switch (category.value) {
- case 'distance': {
- storage.set('unit-calculator-distance-output-unit', newValue);
- break;
- }
- case 'time': {
- storage.set('unit-calculator-time-output-unit', newValue);
- break;
- }
- case 'speed_and_pace': {
- storage.set('unit-calculator-speed-output-unit', newValue);
- break;
- }
- default: {
- break;
- }
- }
-});
-
-/**
* Get the type of a unit
* @param {String} unit The unit
* @returns {String} The type ('decimal' or 'time')
diff --git a/tests/unit/components/TargetSetSelector.spec.js b/tests/unit/components/TargetSetSelector.spec.js
@@ -1,4 +1,4 @@
-import { beforeEach, test, expect, vi } from 'vitest';
+import { test, expect, vi } from 'vitest';
import { shallowMount } from '@vue/test-utils';
import TargetSetSelector from '@/components/TargetSetSelector.vue';
diff --git a/tests/unit/views/PaceCalculator.spec.js b/tests/unit/views/PaceCalculator.spec.js
@@ -75,7 +75,6 @@ test('should not show paces in results table', async () => {
test('should correctly handle null target set', async () => {
// Initialize component
const wrapper = shallowMount(PaceCalculator);
- await wrapper.vm.reloadTargets(); // onActivated method not called in tests
// Switch to invalid target set
await wrapper.findComponent({ name: 'target-set-selector' })
@@ -130,7 +129,6 @@ test('should load selected target set from localStorage', async () => {
// Initialize component
const wrapper = shallowMount(PaceCalculator);
- await wrapper.vm.reloadTargets();
// Assert selection is loaded
expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
diff --git a/tests/unit/views/RaceCalculator.spec.js b/tests/unit/views/RaceCalculator.spec.js
@@ -75,7 +75,6 @@ test('should show paces in results table', async () => {
test('should correctly handle null target set', async () => {
// Initialize component
const wrapper = shallowMount(RaceCalculator);
- await wrapper.vm.reloadTargets(); // onActivated method not called in tests
// Switch to invalid target set
await wrapper.findComponent({ name: 'target-set-selector' })
@@ -189,7 +188,6 @@ test('should load selected target set from localStorage', async () => {
// Initialize component
const wrapper = shallowMount(RaceCalculator);
- await wrapper.vm.reloadTargets();
// Assert selection is loaded
expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
diff --git a/tests/unit/views/SplitCalculator.spec.js b/tests/unit/views/SplitCalculator.spec.js
@@ -9,7 +9,6 @@ beforeEach(() => {
test('should initialize undefined splits to 0:00.00', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets(); // onActivated method not called in tests
// Assert results are correct
const rows = wrapper.findAll('tbody tr');
@@ -46,7 +45,6 @@ test('should correctly load split times from split targets', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Assert results are correct
const rows = wrapper.findAll('tbody tr');
@@ -77,7 +75,6 @@ test('should correctly handle null target set', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Assert results are empty
let rows = wrapper.findAll('tbody tr');
@@ -102,7 +99,6 @@ test('should correctly handle null target set', async () => {
test('should correctly calculate paces and cumulative times from entered split times', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Update split times
await wrapper.findAllComponents({ name: 'time-input' })[0].setValue(420);
@@ -147,7 +143,6 @@ test('should correctly sort split targets', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator)
- await wrapper.vm.reloadTargets();
// Assert results are correct
const rows = wrapper.findAll('tbody tr');
@@ -184,7 +179,6 @@ test('should ignore time based targets', async () => {
}));
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Assert results are correct
const rows = wrapper.findAll('tbody tr');
@@ -221,7 +215,6 @@ test('should correctly save split times with split targets in localStorage', asy
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Update split times
await wrapper.findAllComponents({ name: 'time-input' })[1].setValue(190);
@@ -263,7 +256,6 @@ test('should update results when a new target set is selected', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Assert default split targets are initially loaded
expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet)
@@ -321,7 +313,6 @@ test('should load selected target set from localStorage', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Assert selection is loaded
expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('B');
@@ -352,7 +343,6 @@ test('should load selected target set from localStorage', async () => {
test('should save selected target set to localStorage when modified', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Select a new target set
await wrapper.findComponent({ name: 'target-set-selector' })
@@ -366,7 +356,6 @@ test('should save selected target set to localStorage when modified', async () =
test('should update paces according to default units setting', async () => {
// Initialize component
const wrapper = shallowMount(SplitCalculator);
- await wrapper.vm.reloadTargets();
// Enter split times
await wrapper.findAllComponents({ name: 'time-input' })[0].setValue(300);
diff --git a/tests/unit/views/UnitCalculator.spec.js b/tests/unit/views/UnitCalculator.spec.js
@@ -91,15 +91,23 @@ test('should correctly convert to and from hh:mm:ss', async () => {
test('should correctly load saved inputs', async () => {
// Initialize localStorage
- localStorage.setItem('running-tools.unit-calculator-distance-input-value', '5');
- localStorage.setItem('running-tools.unit-calculator-distance-input-unit', '"kilometers"');
- localStorage.setItem('running-tools.unit-calculator-distance-output-unit', '"miles"');
- localStorage.setItem('running-tools.unit-calculator-time-input-value', '90');
- localStorage.setItem('running-tools.unit-calculator-time-input-unit', '"hh:mm:ss"');
- localStorage.setItem('running-tools.unit-calculator-time-output-unit', '"minutes"');
- localStorage.setItem('running-tools.unit-calculator-speed-input-value', '15');
- localStorage.setItem('running-tools.unit-calculator-speed-input-unit', '"miles_per_hour"');
- localStorage.setItem('running-tools.unit-calculator-speed-output-unit', '"seconds_per_mile"');
+ localStorage.setItem('running-tools.unit-calculator-inputs', JSON.stringify({
+ distance: {
+ inputValue: 5,
+ inputUnit: 'kilometers',
+ outputUnit: 'miles',
+ },
+ time: {
+ inputValue: 90,
+ inputUnit: 'hh:mm:ss',
+ outputUnit: 'minutes',
+ },
+ speed_and_pace: {
+ inputValue: 15,
+ inputUnit: 'miles_per_hour',
+ outputUnit: 'seconds_per_mile',
+ },
+ }));
// Initialize component
const wrapper = shallowMount(UnitCalculator);
@@ -152,13 +160,21 @@ test('should correctly save inputs', async () => {
await wrapper.find('select[aria-label="Output units"]').setValue('seconds_per_mile');
// Initialize localStorage
- expect(localStorage.getItem('running-tools.unit-calculator-distance-input-value')).to.equal('5');
- expect(localStorage.getItem('running-tools.unit-calculator-distance-input-unit')).to.equal('"kilometers"');
- expect(localStorage.getItem('running-tools.unit-calculator-distance-output-unit')).to.equal('"miles"');
- expect(localStorage.getItem('running-tools.unit-calculator-time-input-value')).to.equal('90');
- expect(localStorage.getItem('running-tools.unit-calculator-time-input-unit')).to.equal('"hh:mm:ss"');
- expect(localStorage.getItem('running-tools.unit-calculator-time-output-unit')).to.equal('"minutes"');
- expect(localStorage.getItem('running-tools.unit-calculator-speed-input-value')).to.equal('15');
- expect(localStorage.getItem('running-tools.unit-calculator-speed-input-unit')).to.equal('"miles_per_hour"');
- expect(localStorage.getItem('running-tools.unit-calculator-speed-output-unit')).to.equal('"seconds_per_mile"');
+ expect(localStorage.getItem('running-tools.unit-calculator-inputs')).to.equal(JSON.stringify({
+ distance: {
+ inputValue: 5,
+ inputUnit: 'kilometers',
+ outputUnit: 'miles',
+ },
+ time: {
+ inputValue: 90,
+ inputUnit: 'hh:mm:ss',
+ outputUnit: 'minutes',
+ },
+ speed_and_pace: {
+ inputValue: 15,
+ inputUnit: 'miles_per_hour',
+ outputUnit: 'seconds_per_mile',
+ },
+ }));
});