running-tools

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

commit 1ef20d6cdfc1988f50912ceff2da2c710473d884
parent bdca9057686d5eef92641513c8a356aea9dc4bb2
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Sun,  2 Jun 2024 20:23:09 -0700

Refactor SimpleTargetTable into SingleOutputTable

Data formatting now done in calculator utils instead of table component

Diffstat:
Dsrc/components/SimpleTargetTable.vue | 114-------------------------------------------------------------------------------
Asrc/components/SingleOutputTable.vue | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/utils/calculators.js | 36++++++++++++++++++++++++++++++++++--
Msrc/views/PaceCalculator.vue | 4++--
Msrc/views/RaceCalculator.vue | 4++--
Dtests/unit/components/SimpleTargetTable.spec.js | 123-------------------------------------------------------------------------------
Atests/unit/components/SingleOutputTable.spec.js | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/unit/utils/calculators.spec.js | 63++++++++++++++++++++++++++++++++++++++-------------------------
Mtests/unit/views/PaceCalculator.spec.js | 33+++++++++++++++------------------
Mtests/unit/views/RaceCalculator.spec.js | 49++++++++++++++++++++++++++-----------------------
10 files changed, 320 insertions(+), 309 deletions(-)

diff --git a/src/components/SimpleTargetTable.vue b/src/components/SimpleTargetTable.vue @@ -1,114 +0,0 @@ -<template> - <div class="simple-target-table"> - <table class="results"> - <thead> - <tr> - <th>Distance</th> - - <th>Time</th> - - <th v-if="showPace">Pace</th> - </tr> - </thead> - - <tbody> - <tr v-for="(item, index) in results" :key="index"> - <td :class="item.result === 'distance' ? 'result' : ''"> - {{ formatUtils.formatNumber(item.distanceValue, 0, 2, item.result === 'distance') }} - {{ unitUtils.DISTANCE_UNITS[item.distanceUnit].symbol }} - </td> - - <td :class="item.result === 'time' ? 'result' : ''"> - {{ formatUtils.formatDuration(item.time, 3, 2, item.result === 'time') }} - </td> - - <td v-if="showPace"> - {{ formatUtils.formatDuration(getPace(item), 3, 0, true) }} - / {{ unitUtils.DISTANCE_UNITS[unitUtils.getDefaultDistanceUnit(defaultUnitSystem)] - .symbol }} - </td> - </tr> - - <tr v-if="results.length === 0" class="empty-message"> - <td colspan="4"> - There aren't any targets in this set yet. - </td> - </tr> - </tbody> - </table> - </div> -</template> - -<script setup> -import { computed } from 'vue'; -import formatUtils from '@/utils/format'; -import unitUtils from '@/utils/units'; - -const props = defineProps({ - /** - * The method that generates the target table rows - */ - calculateResult: { - type: Function, - required: true, - }, - - /** - * The target set - */ - targets: { - type: Array, - default: () => [], - }, - - /** - * Whether to show result paces - */ - showPace: { - type: Boolean, - default: false, - }, - - /** - * The unit system to use when showing result paces - */ - defaultUnitSystem: { - type: String, - default: 'metric', - }, -}); - -/** - * The target table results - */ -const results = computed(() => { - // Calculate results - const result = []; - props.targets.forEach((row) => { - // Add result - result.push(props.calculateResult(row)); - }); - - // Sort results by time - result.sort((a, b) => a.time - b.time); - - // Return results - return result; -}); - -/** - * Get the pace of a result - * @param {Object} result The result - */ -function getPace(result) { - return result.time / unitUtils.convertDistance(result.distanceValue, result.distanceUnit, - unitUtils.getDefaultDistanceUnit(props.defaultUnitSystem)); -} -</script> - -<style scoped> -/* target table */ -.results .result { - font-weight: bold; -} -</style> diff --git a/src/components/SingleOutputTable.vue b/src/components/SingleOutputTable.vue @@ -0,0 +1,100 @@ +<template> + <div class="simple-target-table"> + <table class="results"> + <thead> + <tr> + <th>Distance</th> + + <th>Time</th> + + <th v-if="showPace">Pace</th> + </tr> + </thead> + + <tbody> + <tr v-for="(item, index) in results" :key="index"> + <td :class="item.result === 'key' ? 'result' : ''"> + {{ item.key }} + </td> + + <td :class="item.result === 'value' ? 'result' : ''"> + {{ item.value }} + </td> + + <td v-if="showPace"> + {{ item.pace }} + </td> + </tr> + + <tr v-if="results.length === 0" class="empty-message"> + <td colspan="4"> + There aren't any targets in this set yet. + </td> + </tr> + </tbody> + </table> + </div> +</template> + +<script setup> +import { computed } from 'vue'; + +const props = defineProps({ + /** + * The method that generates the target table rows + */ + calculateResult: { + type: Function, + required: true, + }, + + /** + * The target set + */ + targets: { + type: Array, + default: () => [], + }, + + /** + * Whether to show result paces + */ + showPace: { + type: Boolean, + default: false, + }, + + /** + * The unit system to use when showing result paces + */ + defaultUnitSystem: { + type: String, + default: 'metric', + }, +}); + +/** + * The target table results + */ +const results = computed(() => { + // Calculate results + const result = []; + props.targets.forEach((row) => { + // Add result + result.push(props.calculateResult(row)); + }); + + // Sort results + result.sort((a, b) => a.sort - b.sort); + + // Return results + return result; +}); +</script> + +<style scoped> +/* target table */ +.results .result { + font-weight: bold; +} +</style> diff --git a/src/utils/calculators.js b/src/utils/calculators.js @@ -1,8 +1,40 @@ +import formatUtils from '@/utils/format'; import paceUtils from '@/utils/paces'; import raceUtils from '@/utils/races'; import unitUtils from '@/utils/units'; /** + * Format a distance/time result as a key/value result + * @param {Object} result The distance/time result + * @param {String} defaultUnitSystem The default unit system (imperial or metric) + * @returns {Object} The key/value result + */ +function formatDistTimeResult(result, defaultUnitSystem) { + // Calculate numerical pace + const pace = result.time / unitUtils.convertDistance(result.distanceValue, result.distanceUnit, + unitUtils.getDefaultDistanceUnit(defaultUnitSystem)); + + return { + // Convert distance to key string + key: formatUtils.formatNumber(result.distanceValue, 0, 2, result.result === 'distance') + ' ' + + unitUtils.DISTANCE_UNITS[result.distanceUnit].symbol, + + // Convert time to time string + value: formatUtils.formatDuration(result.time, 3, 2, result.result === 'time'), + + // Convert pace to pace string + pace: formatUtils.formatDuration(pace, 3, 0, true) + ' / ' + + unitUtils.DISTANCE_UNITS[unitUtils.getDefaultDistanceUnit(defaultUnitSystem)].symbol, + + // Convert dist/time result to key/value + result: result.result === 'time' ? 'value' : 'key', + + // Use time (in seconds) as sort key + sort: result.time, + }; +} + +/** * Calculate paces from a target * @param {Object} input The input pace * @param {Object} target The pace target @@ -44,7 +76,7 @@ function calculatePaceResults(input, target, defaultUnitSystem) { } // Return result - return result; + return formatDistTimeResult(result, defaultUnitSystem); } /** @@ -130,7 +162,7 @@ function calculateRaceResults(input, target, options, defaultUnitSystem) { } // Return result - return result; + return formatDistTimeResult(result, defaultUnitSystem); } /** diff --git a/src/views/PaceCalculator.vue b/src/views/PaceCalculator.vue @@ -24,7 +24,7 @@ </details> <h2>Equivalent Paces</h2> - <simple-target-table class="output" :calculate-result="x => + <single-output-table class="output" :calculate-result="x => calcUtils.calculatePaceResults(input, x, defaultUnitSystem)" :targets="targetSets[selectedTargetSet] ? targetSets[selectedTargetSet].targets : []"/> </div> @@ -36,7 +36,7 @@ import targetUtils from '@/utils/targets'; import unitUtils from '@/utils/units'; import PaceInput from '@/components/PaceInput.vue'; -import SimpleTargetTable from '@/components/SimpleTargetTable.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 @@ -42,7 +42,7 @@ </details> <h2>Equivalent Race Results</h2> - <simple-target-table class="output" :default-unit-system="defaultUnitSystem" show-pace + <single-output-table class="output" :default-unit-system="defaultUnitSystem" show-pace :calculate-result="x => calcUtils.calculateRaceResults(input, x, options, defaultUnitSystem)" :targets="targetSets[selectedTargetSet] ? targetSets[selectedTargetSet].targets : []"/> </div> @@ -58,7 +58,7 @@ import unitUtils from '@/utils/units'; import PaceInput from '@/components/PaceInput.vue'; import RaceOptions from '@/components/RaceOptions.vue'; -import SimpleTargetTable from '@/components/SimpleTargetTable.vue'; +import SingleOutputTable from '@/components/SingleOutputTable.vue'; import TargetSetSelector from '@/components/TargetSetSelector.vue'; import useStorage from '@/composables/useStorage'; diff --git a/tests/unit/components/SimpleTargetTable.spec.js b/tests/unit/components/SimpleTargetTable.spec.js @@ -1,123 +0,0 @@ -import { test, expect } from 'vitest'; -import { shallowMount } from '@vue/test-utils'; -import SimpleTargetTable from '@/components/SimpleTargetTable.vue'; - -test('results should be correct and sorted by time', () => { - // Initialize component - const wrapper = shallowMount(SimpleTargetTable, { - propsData: { - calculateResult: (row) => ({ - distanceValue: row.distanceValue ? row.distanceValue : row.time / 300, - distanceUnit: row.distanceUnit ? row.distanceUnit : 'miles', - time: row.time ? row.time : row.distanceValue * 300, - result: row.result, - }), - targets: [ - { result: 'time', distanceValue: 5, distanceUnit: 'kilometers' }, - { result: 'time', distanceValue: 1, distanceUnit: 'miles' }, - { result: 'time', distanceValue: 3, distanceUnit: 'miles' }, - { result: 'distance', time: 1230 }, - ], - }, - }); - - // Assert results are correctly rendered - const rows = wrapper.findAll('tbody tr'); - expect(rows[0].findAll('td')[0].element.textContent).to.equal('1 mi'); - expect(rows[0].findAll('td')[1].element.textContent).to.equal('5:00.00'); - expect(rows[0].findAll('td').length).to.equal(2); - expect(rows[1].findAll('td')[0].element.textContent).to.equal('3 mi'); - expect(rows[1].findAll('td')[1].element.textContent).to.equal('15:00.00'); - expect(rows[1].findAll('td').length).to.equal(2); - expect(rows[2].findAll('td')[0].element.textContent).to.equal('4.10 mi'); - expect(rows[2].findAll('td')[1].element.textContent).to.equal('20:30'); - expect(rows[2].findAll('td').length).to.equal(2); - expect(rows[3].findAll('td')[0].element.textContent).to.equal('5 km'); - expect(rows[3].findAll('td')[1].element.textContent).to.equal('25:00.00'); - expect(rows[3].findAll('td').length).to.equal(2); - expect(rows.length).to.equal(4); -}); - -test('should show correct imperial paces when showPace is true', () => { - // Initialize component - const wrapper = shallowMount(SimpleTargetTable, { - propsData: { - calculateResult: (row) => ({ - distanceValue: row.distanceValue ? row.distanceValue : row.time / 300, - distanceUnit: row.distanceUnit ? row.distanceUnit : 'miles', - time: row.time ? row.time : row.distanceValue * 300, - result: row.result, - }), - targets: [ - { result: 'time', distanceValue: 5, distanceUnit: 'kilometers' }, - { result: 'time', distanceValue: 1, distanceUnit: 'miles' }, - { result: 'time', distanceValue: 3, distanceUnit: 'miles' }, - { result: 'distance', time: 1230 }, - ], - defaultUnitSystem: 'imperial', - showPace: true, - }, - }); - - // Assert results are correctly rendered - const rows = wrapper.findAll('tbody tr'); - expect(rows[0].findAll('td')[0].element.textContent).to.equal('1 mi'); - expect(rows[0].findAll('td')[1].element.textContent).to.equal('5:00.00'); - expect(rows[0].findAll('td')[2].element.textContent).to.equal('5:00 / mi'); - expect(rows[0].findAll('td').length).to.equal(3); - expect(rows[1].findAll('td')[0].element.textContent).to.equal('3 mi'); - expect(rows[1].findAll('td')[1].element.textContent).to.equal('15:00.00'); - expect(rows[1].findAll('td')[2].element.textContent).to.equal('5:00 / mi'); - expect(rows[1].findAll('td').length).to.equal(3); - expect(rows[2].findAll('td')[0].element.textContent).to.equal('4.10 mi'); - expect(rows[2].findAll('td')[1].element.textContent).to.equal('20:30'); - expect(rows[2].findAll('td')[2].element.textContent).to.equal('5:00 / mi'); - expect(rows[2].findAll('td').length).to.equal(3); - expect(rows[3].findAll('td')[0].element.textContent).to.equal('5 km'); - expect(rows[3].findAll('td')[1].element.textContent).to.equal('25:00.00'); - expect(rows[3].findAll('td')[2].element.textContent).to.equal('8:03 / mi'); - expect(rows[3].findAll('td').length).to.equal(3); - expect(rows.length).to.equal(4); -}); - -test('should show correct metric paces when showPace is true', () => { - // Initialize component - const wrapper = shallowMount(SimpleTargetTable, { - propsData: { - calculateResult: (row) => ({ - distanceValue: row.distanceValue ? row.distanceValue : row.time / 300, - distanceUnit: row.distanceUnit ? row.distanceUnit : 'miles', - time: row.time ? row.time : row.distanceValue * 300, - result: row.result, - }), - targets: [ - { result: 'time', distanceValue: 5, distanceUnit: 'kilometers' }, - { result: 'time', distanceValue: 1, distanceUnit: 'miles' }, - { result: 'time', distanceValue: 3, distanceUnit: 'miles' }, - { result: 'distance', time: 1230 }, - ], - defaultUnitSystem: 'metric', - showPace: true, - }, - }); - - // Assert results are correctly rendered - const rows = wrapper.findAll('tbody tr'); - expect(rows[0].findAll('td')[0].element.textContent).to.equal('1 mi'); - expect(rows[0].findAll('td')[1].element.textContent).to.equal('5:00.00'); - expect(rows[0].findAll('td')[2].element.textContent).to.equal('3:06 / km'); - expect(rows[0].findAll('td').length).to.equal(3); - expect(rows[1].findAll('td')[0].element.textContent).to.equal('3 mi'); - expect(rows[1].findAll('td')[1].element.textContent).to.equal('15:00.00'); - expect(rows[1].findAll('td')[2].element.textContent).to.equal('3:06 / km'); - expect(rows[1].findAll('td').length).to.equal(3); - expect(rows[2].findAll('td')[0].element.textContent).to.equal('4.10 mi'); - expect(rows[2].findAll('td')[1].element.textContent).to.equal('20:30'); - expect(rows[2].findAll('td')[2].element.textContent).to.equal('3:06 / km'); - expect(rows[2].findAll('td').length).to.equal(3); - expect(rows[3].findAll('td')[0].element.textContent).to.equal('5 km'); - expect(rows[3].findAll('td')[1].element.textContent).to.equal('25:00.00'); - expect(rows[3].findAll('td')[2].element.textContent).to.equal('5:00 / km'); - expect(rows[3].findAll('td').length).to.equal(3); - expect(rows.length).to.equal(4); -}); diff --git a/tests/unit/components/SingleOutputTable.spec.js b/tests/unit/components/SingleOutputTable.spec.js @@ -0,0 +1,103 @@ +import { test, expect } from 'vitest'; +import { shallowMount } from '@vue/test-utils'; +import SingleOutputTable from '@/components/SingleOutputTable.vue'; + +test('results should be correct and sorted by sort key', () => { + // Initialize component + const results = [ + { key: 'key1', value: 'value1', pace: 'pace1', result: 'key', sort: 2 }, + { key: 'key2', value: 'value2', pace: 'pace2', result: 'key', sort: 1 }, + { key: 'key3', value: 'value3', pace: 'pace3', result: 'key', sort: 3 }, + ]; + const wrapper = shallowMount(SingleOutputTable, { + propsData: { + calculateResult: (row) => results[row.id], + targets: [ + { id: 0 }, + { id: 1 }, + { id: 2 }, + ], + }, + }); + + // Assert results are correctly rendered + const rows = wrapper.findAll('tbody tr'); + expect(rows[0].findAll('td')[0].element.textContent).to.equal('key2'); + expect(rows[0].findAll('td')[1].element.textContent).to.equal('value2'); + expect(rows[0].findAll('td').length).to.equal(2); + expect(rows[1].findAll('td')[0].element.textContent).to.equal('key1'); + expect(rows[1].findAll('td')[1].element.textContent).to.equal('value1'); + expect(rows[1].findAll('td').length).to.equal(2); + expect(rows[2].findAll('td')[0].element.textContent).to.equal('key3'); + expect(rows[2].findAll('td')[1].element.textContent).to.equal('value3'); + expect(rows[2].findAll('td').length).to.equal(2); + expect(rows.length).to.equal(3); +}); + +test('results should have correct classes', () => { + // Initialize component + const results = [ + { key: 'key1', value: 'value1', pace: 'pace1', result: 'value', sort: 1 }, + { key: 'key2', value: 'value2', pace: 'pace2', result: 'key', sort: 2 }, + { key: 'key3', value: 'value3', pace: 'pace3', result: 'value', sort: 3 }, + ]; + const wrapper = shallowMount(SingleOutputTable, { + propsData: { + calculateResult: (row) => results[row.id], + targets: [ + { id: 0 }, + { id: 1 }, + { id: 2 }, + ], + }, + }); + + // Assert results are correctly rendered + const rows = wrapper.findAll('tbody tr'); + expect(rows[0].findAll('td')[0].element.classList).toHaveLength(0); + expect(rows[0].findAll('td')[1].element.classList).to.contain(['result']); + expect(rows[0].findAll('td').length).to.equal(2); + expect(rows[1].findAll('td')[0].element.classList).to.contain(['result']); + expect(rows[1].findAll('td')[1].element.classList).toHaveLength(0); + expect(rows[1].findAll('td').length).to.equal(2); + expect(rows[2].findAll('td')[0].element.classList).toHaveLength(0); + expect(rows[2].findAll('td')[1].element.classList).contain(['result']); + expect(rows[2].findAll('td').length).to.equal(2); + expect(rows.length).to.equal(3); +}); + +test('should show correct paces when showPace is true', () => { + // Initialize component + const results = [ + { key: 'key1', value: 'value1', pace: 'pace1', result: 'key', sort: 1 }, + { key: 'key2', value: 'value2', pace: 'pace2', result: 'key', sort: 2 }, + { key: 'key3', value: 'value3', pace: 'pace3', result: 'key', sort: 3 }, + ]; + const wrapper = shallowMount(SingleOutputTable, { + propsData: { + calculateResult: (row) => results[row.id], + targets: [ + { id: 0 }, + { id: 1 }, + { id: 2 }, + ], + showPace: true, + }, + }); + + // Assert results are correctly rendered + const rows = wrapper.findAll('tbody tr'); + expect(rows[0].findAll('td')[0].element.textContent).to.equal('key1'); + expect(rows[0].findAll('td')[1].element.textContent).to.equal('value1'); + expect(rows[0].findAll('td')[2].element.textContent).to.equal('pace1'); + expect(rows[0].findAll('td').length).to.equal(3); + expect(rows[1].findAll('td')[0].element.textContent).to.equal('key2'); + expect(rows[1].findAll('td')[1].element.textContent).to.equal('value2'); + expect(rows[1].findAll('td')[2].element.textContent).to.equal('pace2'); + expect(rows[1].findAll('td').length).to.equal(3); + expect(rows[2].findAll('td')[0].element.textContent).to.equal('key3'); + expect(rows[2].findAll('td')[1].element.textContent).to.equal('value3'); + expect(rows[2].findAll('td')[2].element.textContent).to.equal('pace3'); + expect(rows[2].findAll('td').length).to.equal(3); + expect(rows.length).to.equal(3); +}); diff --git a/tests/unit/utils/calculators.spec.js b/tests/unit/utils/calculators.spec.js @@ -13,13 +13,14 @@ test('should correctly calculate pace times', () => { result: 'time', }; - const result = calculatorUtils.calculatePaceResults(input, target, {}); + const result = calculatorUtils.calculatePaceResults(input, target, 'metric'); expect(result).to.deep.equal({ - distanceValue: 20, - distanceUnit: 'meters', - time: 2, - result: 'time', + key: '20 m', + value: '0:02.00', + pace: '1:40 / km', + result: 'value', + sort: 2, }); }); @@ -37,10 +38,17 @@ test('should correctly calculate pace distances according to default units setti const result1 = calculatorUtils.calculatePaceResults(input, target, 'metric'); const result2 = calculatorUtils.calculatePaceResults(input, target, 'imperial'); - expect(result1.distanceValue).to.be.closeTo(1.609, 0.001); - expect(result1.distanceUnit).to.equal('kilometers'); - expect(result2.distanceValue).to.be.closeTo(1.000, 0.001); - expect(result2.distanceUnit).to.equal('miles'); + expect(result1.key).to.equal('1.61 km'); + expect(result1.value).to.equal('10:00'); + expect(result1.pace).to.equal('6:13 / km'); + expect(result1.result).to.equal('key'); + expect(result1.sort).to.be.closeTo(600, 0.01); + + expect(result2.key).to.equal('1.00 mi'); + expect(result2.value).to.equal('10:00'); + expect(result2.pace).to.equal('10:00 / mi'); + expect(result2.result).to.equal('key'); + expect(result2.sort).to.be.closeTo(600, 0.01); }); test('should correctly predict race times', () => { @@ -61,10 +69,11 @@ test('should correctly predict race times', () => { const result = calculatorUtils.calculateRaceResults(input, target, options, 'imperial'); - expect(result.time).to.be.closeTo(2495, 1); - expect(result.distanceValue).to.equal(10); - expect(result.distanceUnit).to.equal('kilometers'); - expect(result.result).to.equal('time'); + expect(result.key).to.equal('10 km'); + expect(result.value).to.equal('41:34.80'); + expect(result.pace).to.equal('6:42 / mi'); + expect(result.result).to.equal('value'); + expect(result.sort).to.be.closeTo(2494.80, 0.01); }); test('should correctly calculate race distances according to default units setting', () => { @@ -85,14 +94,17 @@ test('should correctly calculate race distances according to default units setti const result1 = calculatorUtils.calculateRaceResults(input, target, options, 'metric'); const result2 = calculatorUtils.calculateRaceResults(input, target, options, 'imperial'); - expect(result1.distanceValue).to.be.closeTo(10, 0.01); - expect(result1.distanceUnit).to.equal('kilometers'); - expect(result1.time).to.equal(2495); - expect(result1.result).to.equal('distance'); - expect(result2.distanceValue).to.be.closeTo(6.214, 0.01); - expect(result2.distanceUnit).to.equal('miles'); - expect(result2.time).to.equal(2495); - expect(result2.result).to.equal('distance'); + expect(result1.key).to.equal('10.00 km'); + expect(result1.value).to.equal('41:35'); + expect(result1.pace).to.equal('4:09 / km'); + expect(result1.result).to.equal('key'); + expect(result1.sort).to.equal(2495); + + expect(result2.key).to.equal('6.21 mi'); + expect(result2.value).to.equal('41:35'); + expect(result2.pace).to.equal('6:41 / mi'); + expect(result2.result).to.equal('key'); + expect(result2.sort).to.equal(2495); }); test('should correctly predict race times according to race options', () => { @@ -113,10 +125,11 @@ test('should correctly predict race times according to race options', () => { const result = calculatorUtils.calculateRaceResults(input, target, options, 'imperial'); - expect(result.time).to.be.closeTo(1031, 1); - expect(result.distanceValue).to.equal(5); - expect(result.distanceUnit).to.equal('kilometers'); - expect(result.result).to.equal('time'); + expect(result.key).to.equal('5 km'); + expect(result.value).to.equal('17:11.77'); + expect(result.pace).to.equal('5:32 / mi'); + expect(result.result).to.equal('value'); + expect(result.sort).to.be.closeTo(1031.77, 0.01); }); test('should correctly calculate race statistics', () => { diff --git a/tests/unit/views/PaceCalculator.spec.js b/tests/unit/views/PaceCalculator.spec.js @@ -19,7 +19,7 @@ test('should correctly calculate time results', async () => { }); // Calculate result - const calculateResult = wrapper.findComponent({ name: 'simple-target-table' }).vm.calculateResult; + const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult; const result = calculateResult({ distanceValue: 20, distanceUnit: 'meters', @@ -28,10 +28,11 @@ test('should correctly calculate time results', async () => { // Assert result is correct expect(result).to.deep.equal({ - distanceValue: 20, - distanceUnit: 'meters', - time: 2, - result: 'time', + key: '20 m', + value: '0:02.00', + pace: '2:41 / mi', + result: 'value', + sort: 2, }); }); @@ -50,22 +51,18 @@ test('should correctly calculate distance results according to default units set await wrapper.find('select[aria-label="Default units"]').setValue('metric'); // Get calculate result function - const calculateResult = wrapper.findComponent({ name: 'simple-target-table' }).vm.calculateResult; + const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult; // Assert result is correct let result = calculateResult({ result: 'distance', time: 600 }); - expect(result.distanceValue).to.be.closeTo(1.609, 0.001); - expect(result.distanceUnit).to.equal('kilometers'); + expect(result.key).to.equal('1.61 km'); // Change default units await wrapper.find('select[aria-label="Default units"]').setValue('imperial'); // Assert result is correct result = calculateResult({ result: 'distance', time: 600 }); - expect(result.distanceValue).to.equal(1); - expect(result.distanceUnit).to.equal('miles'); - expect(result.time).to.equal(600); - expect(result.result).to.equal('distance'); + expect(result.key).to.equal('1.00 mi'); }); test('should not show paces in results table', async () => { @@ -73,7 +70,7 @@ test('should not show paces in results table', async () => { const wrapper = shallowMount(PaceCalculator); // Assert paces are not shown in results table - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.showPace).to.equal(false); + expect(wrapper.findComponent({ name: 'single-output-table' }).vm.showPace).to.equal(false); }); test('should correctly handle null target set', async () => { @@ -84,16 +81,16 @@ test('should correctly handle null target set', async () => { await wrapper.findComponent({ name: 'target-set-selector' }) .setValue('does_not_exist', 'selectedTargetSet'); - // Assert empty array passed to SimpleTargetTable component - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.targets).to.deep.equal([]); + // 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'); - // Assert valid targets passed to SimpleTargetTable component + // Assert valid targets passed to SingleOutputTable component const paceTargets = targetUtils.defaultTargetSets._pace_targets.targets; - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.targets) + expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets) .to.deep.equal(paceTargets); }); @@ -164,7 +161,7 @@ test('should load selected target set from localStorage', async () => { // Assert selection is loaded expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet) .to.equal('B'); - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.targets) + expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets) .to.deep.equal(targetSet2.targets); }); diff --git a/tests/unit/views/RaceCalculator.spec.js b/tests/unit/views/RaceCalculator.spec.js @@ -19,7 +19,7 @@ test('should correctly predict race times', async () => { }); // Calculate result - const calculateResult = wrapper.findComponent({ name: 'simple-target-table' }).vm.calculateResult; + const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult; const result = calculateResult({ distanceValue: 10, distanceUnit: 'kilometers', @@ -27,10 +27,11 @@ test('should correctly predict race times', async () => { }); // Assert result is correct - expect(result.time).to.be.closeTo(2495, 1); - expect(result.distanceValue).to.equal(10); - expect(result.distanceUnit).to.equal('kilometers'); - expect(result.result).to.equal('time'); + expect(result.key).to.equal('10 km'); + expect(result.value).to.equal('41:34.80'); + expect(result.pace).to.equal('6:42 / mi'); + expect(result.result).to.equal('value'); + expect(result.sort).to.be.closeTo(2494.80, 0.01); }); test('should correctly calculate distance results according to default units setting', async () => { @@ -48,24 +49,26 @@ test('should correctly calculate distance results according to default units set await wrapper.find('select[aria-label="Default units"]').setValue('metric'); // Get calculate result function - const calculateResult = wrapper.findComponent({ name: 'simple-target-table' }).vm.calculateResult; + const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult; // Assert result is correct let result = calculateResult({ result: 'distance', time: 2495 }); - expect(result.distanceValue).to.be.closeTo(10, 0.01); - expect(result.distanceUnit).to.equal('kilometers'); - expect(result.time).to.equal(2495); - expect(result.result).to.equal('distance'); + expect(result.key).to.equal('10.00 km'); + expect(result.value).to.equal('41:35'); + expect(result.pace).to.equal('4:09 / km'); + expect(result.result).to.equal('key'); + expect(result.sort).to.equal(2495); // Change default units await wrapper.find('select[aria-label="Default units"]').setValue('imperial'); // Assert result is correct result = calculateResult({ result: 'distance', time: 2495 }); - expect(result.distanceValue).to.be.closeTo(6.214, 0.01); - expect(result.distanceUnit).to.equal('miles'); - expect(result.time).to.equal(2495); - expect(result.result).to.equal('distance'); + expect(result.key).to.equal('6.21 mi'); + expect(result.value).to.equal('41:35'); + expect(result.pace).to.equal('6:41 / mi'); + expect(result.result).to.equal('key'); + expect(result.sort).to.equal(2495); }); test('should show paces in results table', async () => { @@ -73,7 +76,7 @@ test('should show paces in results table', async () => { const wrapper = shallowMount(RaceCalculator); // Assert paces are shown in results table - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.showPace).to.equal(true); + expect(wrapper.findComponent({ name: 'single-output-table' }).vm.showPace).to.equal(true); }); test('should correctly handle null target set', async () => { @@ -84,16 +87,16 @@ test('should correctly handle null target set', async () => { await wrapper.findComponent({ name: 'target-set-selector' }) .setValue('does_not_exist', 'selectedTargetSet'); - // Assert empty array passed to SimpleTargetTable component - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.targets).to.deep.equal([]); + // 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'); - // Assert valid targets passed to SimpleTargetTable component + // Assert valid targets passed to SingleOutputTable component const raceTargets = targetUtils.defaultTargetSets._race_targets.targets; - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.targets) + expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets) .to.deep.equal(raceTargets); }); @@ -138,7 +141,7 @@ test('should correctly calculate results according to advanced model options', a }); // Calculate result - const calculateResult = wrapper.findComponent({ name: 'simple-target-table' }).vm.calculateResult; + const calculateResult = wrapper.findComponent({ name: 'single-output-table' }).vm.calculateResult; let result = calculateResult({ distanceValue: 10, distanceUnit: 'kilometers', @@ -146,7 +149,7 @@ test('should correctly calculate results according to advanced model options', a }); // Assert result is correct - expect(result.time).to.be.closeTo(2502, 1); + expect(result.value).to.equal('41:41.92'); // Update Riegel Exponent await wrapper.findComponent({ name: 'RaceOptions' }).setValue({ @@ -162,7 +165,7 @@ test('should correctly calculate results according to advanced model options', a }); // Assert result is correct - expect(result.time).to.equal(2400); + expect(result.value).to.equal('40:00.00'); }); test('should load input race from localStorage', async () => { @@ -232,7 +235,7 @@ test('should load selected target set from localStorage', async () => { // Assert selection is loaded expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet) .to.equal('B'); - expect(wrapper.findComponent({ name: 'simple-target-table' }).vm.targets) + expect(wrapper.findComponent({ name: 'single-output-table' }).vm.targets) .to.deep.equal(targetSet2.targets); });