running-tools

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

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 });