SplitCalculator.spec.js (8201B)
1 import { beforeEach, test, expect } from 'vitest'; 2 import { shallowMount } from '@vue/test-utils'; 3 import SplitCalculator from '@/views/SplitCalculator.vue'; 4 import { defaultTargetSets } from '@/core/targets'; 5 import { detectDefaultUnitSystem } from '@/core/units'; 6 7 beforeEach(() => { 8 localStorage.clear(); 9 }); 10 11 test('should initialize options to default values', async () => { 12 // Initialize component 13 const wrapper = shallowMount(SplitCalculator); 14 15 // Assert options are initialized 16 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.globalOptions 17 .defaultUnitSystem).to.equal(detectDefaultUnitSystem()); 18 expect(wrapper.findComponent({ name: 'split-output-table' }).vm.defaultUnitSystem) 19 .to.equal(detectDefaultUnitSystem()); 20 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({ 21 selectedTargetSet: '_split_targets', 22 }); 23 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.targetSets) 24 .to.deep.equal({ _split_targets: defaultTargetSets._split_targets }); 25 expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue) 26 .to.deep.equal(defaultTargetSets._split_targets.targets); 27 }); 28 29 test('should load options from localStorage', async () => { 30 const targetSets = { 31 '_split_targets': { 32 name: 'Split targets', 33 targets: [ 34 { type: 'distance', distanceValue: 1, distanceUnit: 'miles' }, 35 { type: 'distance', distanceValue: 2, distanceUnit: 'miles' }, 36 { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' }, 37 ], 38 }, 39 'B': { 40 name: 'Split targets #2', 41 targets: [ 42 { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers', split: 180 }, 43 { type: 'distance', distanceValue: 2, distanceUnit: 'kilometers', split: 190 }, 44 { type: 'distance', distanceValue: 3000, distanceUnit: 'meters', split: 200 }, 45 ], 46 }, 47 }; 48 49 // Initialize localStorage 50 localStorage.setItem('running-tools.global-options', JSON.stringify({ 51 defaultUnitSystem: 'imperial', 52 racePredictionOptions: { 53 model: 'AverageModel', 54 riegelExponent: 1.06, 55 }, 56 })); 57 localStorage.setItem('running-tools.split-calculator-target-sets', JSON.stringify(targetSets)); 58 localStorage.setItem('running-tools.split-calculator-options', JSON.stringify({ 59 selectedTargetSet: 'B', 60 })); 61 62 // Initialize component 63 const wrapper = shallowMount(SplitCalculator); 64 65 // Assert options are loaded 66 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.globalOptions 67 .defaultUnitSystem).to.equal('imperial'); 68 expect(wrapper.findComponent({ name: 'split-output-table' }).vm.defaultUnitSystem) 69 .to.equal('imperial'); 70 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({ 71 selectedTargetSet: 'B', 72 }); 73 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.targetSets) 74 .to.deep.equal(targetSets); 75 expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue) 76 .to.deep.equal(targetSets.B.targets); 77 }); 78 79 test('should save options to localStorage when modified', async () => { 80 const targetSets1 = { 81 '_split_targets': { 82 name: 'Split targets', 83 targets: [ 84 { type: 'distance', distanceValue: 1, distanceUnit: 'miles' }, 85 { type: 'distance', distanceValue: 2, distanceUnit: 'miles' }, 86 { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' }, 87 ], 88 }, 89 'B': { 90 name: 'Split targets #2', 91 targets: [ 92 { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers', split: 180 }, 93 { type: 'distance', distanceValue: 2, distanceUnit: 'kilometers', split: 190 }, 94 { type: 'distance', distanceValue: 3000, distanceUnit: 'meters', split: 200 }, 95 ], 96 }, 97 }; 98 const targetSets2 = { 99 '_split_targets': { 100 name: 'Split targets', 101 targets: [ 102 { type: 'distance', distanceValue: 1, distanceUnit: 'miles' }, 103 { type: 'distance', distanceValue: 2, distanceUnit: 'miles' }, 104 { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' }, 105 ], 106 }, 107 'B': { 108 name: 'Split targets #2', 109 targets: [ 110 // split times modified: 111 { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers', split: 185 }, 112 { type: 'distance', distanceValue: 2, distanceUnit: 'kilometers', split: 195 }, 113 { type: 'distance', distanceValue: 3000, distanceUnit: 'meters', split: 205 }, 114 ], 115 }, 116 }; 117 118 // Initialize component 119 const wrapper = shallowMount(SplitCalculator); 120 121 // Set default units setting 122 await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({ 123 defaultUnitSystem: 'metric', 124 racePredictionOptions: { 125 model: 'AverageModel', 126 riegelExponent: 1.06, 127 }, 128 }, 'globalOptions'); 129 130 // New default units should be saved to localStorage 131 expect(localStorage.getItem('running-tools.global-options')).to.equal(JSON.stringify({ 132 defaultUnitSystem: 'metric', 133 racePredictionOptions: { 134 model: 'AverageModel', 135 riegelExponent: 1.06, 136 }, 137 })); 138 139 // Update default units setting 140 await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({ 141 defaultUnitSystem: 'imperial', 142 racePredictionOptions: { 143 model: 'AverageModel', 144 riegelExponent: 1.06, 145 }, 146 }, 'globalOptions'); 147 148 // New default units should be saved to localStorage 149 expect(localStorage.getItem('running-tools.global-options')).to.equal(JSON.stringify({ 150 defaultUnitSystem: 'imperial', 151 racePredictionOptions: { 152 model: 'AverageModel', 153 riegelExponent: 1.06, 154 }, 155 })); 156 157 // Update target sets and selected target set via AdvancedOptionsInput 158 await wrapper.findComponent({ name: 'advanced-options-input' }).setValue(targetSets1, 159 'targetSets'); 160 await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({ 161 selectedTargetSet: 'B', 162 }, 'options'); 163 164 // Assert data saved to localStorage 165 expect(localStorage.getItem('running-tools.split-calculator-target-sets')) 166 .to.equal(JSON.stringify(targetSets1)); 167 expect(localStorage.getItem('running-tools.split-calculator-options')).to.equal(JSON.stringify({ 168 selectedTargetSet: 'B', 169 })); 170 171 // Update target sets via SplitOutputTable 172 await wrapper.findComponent({ name: 'split-output-table' }).setValue(targetSets2.B.targets); 173 174 // Assert data saved to localStorage 175 expect(localStorage.getItem('running-tools.split-calculator-target-sets')) 176 .to.equal(JSON.stringify(targetSets2)); 177 expect(localStorage.getItem('running-tools.split-calculator-options')).to.equal(JSON.stringify({ 178 selectedTargetSet: 'B', 179 })); 180 }); 181 182 test('should correctly handle null target set', async () => { 183 // Initialize localStorage 184 localStorage.setItem('running-tools.split-calculator-options', JSON.stringify({ 185 selectedTargetSet: 'does_not_exist', 186 })); 187 188 // Initialize component 189 const wrapper = shallowMount(SplitCalculator); 190 191 // Assert selection is loaded 192 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.options).to.deep.equal({ 193 selectedTargetSet: 'does_not_exist', 194 }); 195 196 // Assert empty array passed to SplitOutputTable 197 expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue).to.deep.equal([]); 198 199 // Switch to valid target set 200 await wrapper.findComponent({ name: 'advanced-options-input' }).setValue({ 201 selectedTargetSet: '_split_targets', 202 }, 'options'); 203 204 // Assert non-empty target set passed to SplitOutputTable 205 expect(wrapper.findComponent({ name: 'split-output-table' }).vm.modelValue).to.deep.equal([ 206 { type: 'distance', distanceValue: 1, distanceUnit: 'miles' }, 207 { type: 'distance', distanceValue: 2, distanceUnit: 'miles' }, 208 { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' }, 209 ]); 210 }); 211 212 test('should correctly set AdvancedOptionsInput type prop', async () => { 213 // Initialize component 214 const wrapper = shallowMount(SplitCalculator); 215 216 // Assert type prop is correctly set 217 expect(wrapper.findComponent({ name: 'advanced-options-input' }).vm.type).to.equal('split'); 218 });