running-tools

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

AdvancedOptionsInput.spec.js (17564B)


      1 import { test, expect } from 'vitest';
      2 import { shallowMount } from '@vue/test-utils';
      3 import AdvancedOptionsInput from '@/components/AdvancedOptionsInput.vue';
      4 
      5 test('should be correctly render pace options according to props', () => {
      6   // Initialize component
      7   const wrapper = shallowMount(AdvancedOptionsInput, {
      8     propsData: {
      9       globalOptions: {
     10         defaultUnitSystem: 'metric',
     11         racePredictionOptions: {
     12           model: 'CameronModel',
     13           riegelExponent: 1.30,
     14         },
     15       },
     16       options: {
     17         input: {
     18           distanceValue: 5,
     19           distanceUnit: 'kilometers',
     20           time: 1200,
     21         },
     22         selectedTargetSet: 'B',
     23       },
     24       targetSets: {
     25         'A': {
     26           name: '1st target set',
     27           targets: [
     28             { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
     29             { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
     30             { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
     31           ],
     32         },
     33         'B': {
     34           name: '2nd target set',
     35           targets: [
     36             { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
     37             { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
     38             { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
     39           ],
     40         },
     41       },
     42       type: 'pace',
     43     },
     44   });
     45 
     46   // Assert all input fields are correct
     47   expect(wrapper.find('select[aria-label="Default units"]').element.value).to.equal('metric');
     48   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
     49     .equal('B');
     50   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.targetSets).to.deep.equal({
     51     'A': {
     52       name: '1st target set',
     53       targets: [
     54         { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
     55         { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
     56         { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
     57       ],
     58     },
     59     'B': {
     60       name: '2nd target set',
     61       targets: [
     62         { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
     63         { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
     64         { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
     65       ],
     66     },
     67   });
     68   expect(wrapper.findAll('select[aria-label="Workout name customization"]')).to.have
     69     .length(0);
     70   expect(wrapper.findAll('input[aria-label="Batch column label"]')).to.have
     71     .length(0);
     72   expect(wrapper.findAll('select[aria-label="Prediction model"]')).to.have.length(0);
     73   expect(wrapper.findAllComponents({ name: 'decimal-input' })).to.have.length(0);
     74 });
     75 
     76 test('should be correctly render race options according to props', () => {
     77   // Initialize component
     78   const wrapper = shallowMount(AdvancedOptionsInput, {
     79     propsData: {
     80       globalOptions: {
     81         defaultUnitSystem: 'metric',
     82         racePredictionOptions: {
     83           model: 'PurdyPointsModel',
     84           riegelExponent: 1.2,
     85         },
     86       },
     87       options: {
     88         input: {
     89           distanceValue: 5,
     90           distanceUnit: 'kilometers',
     91           time: 1200,
     92         },
     93         selectedTargetSet: '_new',
     94       },
     95       type: 'race',
     96       targetSets: {},
     97     },
     98   });
     99 
    100   // Assert input fields are correct
    101   expect(wrapper.find('select[aria-label="Default units"]').element.value).to
    102     .equal('metric');
    103   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
    104     .equal('_new');
    105   expect(wrapper.findAll('select[aria-label="Workout name customization"]')).to.have
    106     .length(0);
    107   expect(wrapper.findAll('input[aria-label="Batch column label"]')).to.have
    108     .length(0);
    109   expect(wrapper.find('select[aria-label="Prediction model"]').element.value).to
    110     .equal('PurdyPointsModel');
    111   expect(wrapper.findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(1.2);
    112   expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false);
    113 });
    114 
    115 test('should render riegel exponent field only for supported race prediction models', async () => {
    116   // Initialize component
    117   const wrapper = shallowMount(AdvancedOptionsInput, {
    118     propsData: {
    119       globalOptions: {
    120         defaultUnitSystem: 'metric',
    121         racePredictionOptions: {
    122           model: 'AverageModel',
    123           riegelExponent: 1.2,
    124         },
    125       },
    126       options: {
    127         input: {
    128           distanceValue: 5,
    129           distanceUnit: 'kilometers',
    130           time: 1200,
    131         },
    132         selectedTargetSet: '_new',
    133       },
    134       type: 'race',
    135       targetSets: {},
    136     },
    137     attachTo: document.body,
    138   });
    139 
    140   // Assert field is visible for Average model
    141   expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(true);
    142 
    143   // Assert field is not visible for Purdy Points model
    144   await wrapper.find('select[aria-label="Prediction model"]').setValue('PurdyPointsModel');
    145   expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false);
    146 
    147   // Assert field is not visible for VO2 Max model
    148   await wrapper.find('select[aria-label="Prediction model"]').setValue('VO2MaxModel');
    149   expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false);
    150 
    151   // Assert field is not visible for Cameron model
    152   await wrapper.find('select[aria-label="Prediction model"]').setValue('CameronModel');
    153   expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(false);
    154 
    155   // Assert field is not visible for Riegel model
    156   await wrapper.find('select[aria-label="Prediction model"]').setValue('RiegelModel');
    157   expect(wrapper.findComponent({ name: 'decimal-input' }).isVisible()).to.equal(true);
    158 });
    159 
    160 test('should be correctly render split options according to props', () => {
    161   // Initialize component
    162   const wrapper = shallowMount(AdvancedOptionsInput, {
    163     propsData: {
    164       globalOptions: {
    165         defaultUnitSystem: 'metric',
    166         racePredictionOptions: {
    167           model: 'CameronModel',
    168           riegelExponent: 1.30,
    169         },
    170       },
    171       options: {
    172         selectedTargetSet: '_new',
    173       },
    174       targetSets: {},
    175       type: 'split',
    176     },
    177   });
    178 
    179   // Assert input fields are correct
    180   expect(wrapper.find('select[aria-label="Default units"]').element.value).to
    181     .equal('metric');
    182   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
    183     .equal('_new');
    184   expect(wrapper.findAll('select[aria-label="Workout name customization"]')).to.have
    185     .length(0);
    186   expect(wrapper.findAll('input[aria-label="Batch column label"]')).to.have
    187     .length(0);
    188   expect(wrapper.findAll('select[aria-label="Prediction model"]')).to.have.length(0);
    189   expect(wrapper.findAllComponents({ name: 'decimal-input' })).to.have.length(0);
    190 });
    191 
    192 test('should be correctly render workout options according to props', () => {
    193   // Initialize component
    194   const wrapper = shallowMount(AdvancedOptionsInput, {
    195     propsData: {
    196       globalOptions: {
    197         defaultUnitSystem: 'metric',
    198         racePredictionOptions: {
    199           model: 'PurdyPointsModel',
    200           riegelExponent: 1.2,
    201         },
    202       },
    203       options: {
    204         customTargetNames: true,
    205         input: {
    206           distanceValue: 5,
    207           distanceUnit: 'kilometers',
    208           time: 1200,
    209         },
    210         selectedTargetSet: '_new',
    211       },
    212       targetSets: {},
    213       type: 'workout',
    214     },
    215   });
    216 
    217   // Assert input fields are correct
    218   expect(wrapper.find('select[aria-label="Default units"]').element.value).to.equal('metric');
    219   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to
    220     .equal('_new');
    221   expect(wrapper.find('select[aria-label="Workout name customization"]').element.value).to
    222     .equal('true');
    223   expect(wrapper.findAll('input[aria-label="Batch column label"]')).to.have
    224     .length(0);
    225   expect(wrapper.find('select[aria-label="Prediction model"]').element.value).to
    226     .equal('PurdyPointsModel');
    227   expect(wrapper.findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(1.2);
    228 });
    229 
    230 test('should only show batch column label field when applicable', async () => {
    231   // Initialize component with workout target name customization enabled
    232   const wrapper = shallowMount(AdvancedOptionsInput, {
    233     propsData: {
    234       globalOptions: {
    235         defaultUnitSystem: 'metric',
    236         racePredictionOptions: {
    237           model: 'CameronModel',
    238           riegelExponent: 1.30,
    239         },
    240       },
    241       options: {
    242         customTargetNames: true,
    243         input: {
    244           distanceValue: 5,
    245           distanceUnit: 'kilometers',
    246           time: 1200,
    247         },
    248         selectedTargetSet: '_new',
    249       },
    250       targetSets: {},
    251       type: 'workout',
    252     },
    253     attachTo: document.body,
    254   });
    255 
    256   // Assert batch column label field is hidden
    257   expect(wrapper.findAll('input[aria-label="Batch column label"]')).to.have
    258     .length(0);
    259 
    260   // Add batchOptions but disable workout target name customization
    261   await wrapper.setProps({
    262     batchOptions: { // added
    263       calculator: 'workout',
    264       increment: 32,
    265       input: {
    266         distanceValue: 2,
    267         distanceUnit: 'miles',
    268         time: 600,
    269       },
    270       label: 'foo',
    271       rows: 15,
    272     },
    273     globalOptions: {
    274       defaultUnitSystem: 'metric',
    275       racePredictionOptions: {
    276         model: 'CameronModel',
    277         riegelExponent: 1.30,
    278       },
    279     },
    280     options: {
    281       customTargetNames: false, // disabled
    282       input: {
    283         distanceValue: 5,
    284         distanceUnit: 'kilometers',
    285         time: 1200,
    286       },
    287       selectedTargetSet: '_new',
    288     },
    289     targetSets: {},
    290     type: 'workout',
    291   });
    292 
    293   // Assert batch column label field is still hidden
    294   expect(wrapper.find('input[aria-label="Batch column label"]').isVisible()).to.equal(false);
    295 
    296   // Enable workout target name customization
    297   await wrapper.setProps({
    298     batchOptions: {
    299       calculator: 'workout',
    300       increment: 32,
    301       input: {
    302         distanceValue: 2,
    303         distanceUnit: 'miles',
    304         time: 600,
    305       },
    306       label: 'foo',
    307       rows: 15,
    308     },
    309     globalOptions: {
    310       defaultUnitSystem: 'metric',
    311       racePredictionOptions: {
    312         model: 'CameronModel',
    313         riegelExponent: 1.30,
    314       },
    315     },
    316     options: {
    317       customTargetNames: true, // enabled
    318       input: {
    319         distanceValue: 5,
    320         distanceUnit: 'kilometers',
    321         time: 1200,
    322       },
    323       selectedTargetSet: '_new',
    324     },
    325     targetSets: {},
    326     type: 'workout',
    327   });
    328 
    329   // Assert batch column label field is now visible
    330   expect(wrapper.find('input[aria-label="Batch column label"]').isVisible()).to.equal(true);
    331   expect(wrapper.find('input[aria-label="Batch column label"]').element.placeholder).to.equal('2 mi')
    332   expect(wrapper.find('input[aria-label="Batch column label"]').element.value).to.equal('foo')
    333 
    334   // Switch to race calculator
    335   await wrapper.setProps({
    336     batchOptions: {
    337       calculator: 'workout',
    338       increment: 32,
    339       input: {
    340         distanceValue: 2,
    341         distanceUnit: 'miles',
    342         time: 600,
    343       },
    344       label: 'foo',
    345       rows: 15,
    346     },
    347     globalOptions: {
    348       defaultUnitSystem: 'metric',
    349       racePredictionOptions: {
    350         model: 'CameronModel',
    351         riegelExponent: 1.30,
    352       },
    353     },
    354     options: {
    355       input: {
    356         distanceValue: 5,
    357         distanceUnit: 'kilometers',
    358         time: 1200,
    359       },
    360       selectedTargetSet: '_new',
    361     },
    362     targetSets: {},
    363     type: 'race', // changed
    364   });
    365 
    366   // Assert batch column label field is hidden again
    367   expect(wrapper.findAll('input[aria-label="Batch column label"]')).to.have
    368     .length(0);
    369 });
    370 
    371 test('should pass correct props to TargetSetSelector', async () => {
    372   // Initialize component
    373   const wrapper = shallowMount(AdvancedOptionsInput, {
    374     propsData: {
    375       globalOptions: {
    376         defaultUnitSystem: 'metric',
    377         racePredictionOptions: {
    378           model: 'CameronModel',
    379           riegelExponent: 1.30,
    380         },
    381       },
    382       options: {
    383         customTargetNames: false,
    384         input: {
    385           distanceValue: 5,
    386           distanceUnit: 'kilometers',
    387           time: 1200,
    388         },
    389         selectedTargetSet: 'B',
    390       },
    391       targetSets: {
    392         'A': {
    393           name: '1st target set v2',
    394           targets: [
    395             { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
    396             { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
    397             { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
    398           ],
    399         },
    400         'B': {
    401           name: '2nd target set',
    402           targets: [
    403             { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
    404             { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
    405             { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
    406           ],
    407         },
    408       },
    409       type: 'workout',
    410     },
    411   });
    412 
    413   // Assert props are correct
    414   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.selectedTargetSet).to.equal('B');
    415   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.targetSets).to.deep.equal({
    416     'A': {
    417       name: '1st target set v2',
    418       targets: [
    419         { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
    420         { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
    421         { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
    422       ],
    423     },
    424     'B': {
    425       name: '2nd target set',
    426       targets: [
    427         { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
    428         { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
    429         { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
    430       ],
    431     },
    432   });
    433   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.customWorkoutNames)
    434     .to.equal(false);
    435 
    436   // Update options
    437   await wrapper.find('select[aria-label="Workout name customization"]').setValue('true');
    438 
    439   // Assert props are updated
    440   expect(wrapper.findComponent({ name: 'target-set-selector' }).vm.customWorkoutNames)
    441     .to.equal(true);
    442 });
    443 
    444 test('should emit input events when options are modified', async () => {
    445   // Initialize component
    446   const wrapper = shallowMount(AdvancedOptionsInput, {
    447     propsData: {
    448       globalOptions: {
    449         defaultUnitSystem: 'metric',
    450         racePredictionOptions: {
    451           model: 'AverageModel',
    452           riegelExponent: 1.06,
    453         },
    454       },
    455       options: {
    456         customTargetNames: false,
    457         input: {
    458           distanceValue: 5,
    459           distanceUnit: 'kilometers',
    460           time: 1200,
    461         },
    462         selectedTargetSet: '_new',
    463       },
    464       targetSets: {},
    465       type: 'workout',
    466     },
    467   });
    468 
    469   // Update options
    470   await wrapper.find('select[aria-label="Default units"]').setValue('imperial');
    471   await wrapper.findComponent({ name: 'target-set-selector' }).setValue({
    472     'A': {
    473       name: '1st target set v2',
    474       targets: [
    475         { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
    476         { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
    477         { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
    478       ],
    479     },
    480     'B': {
    481       name: '2nd target set',
    482       targets: [
    483         { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
    484         { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
    485         { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
    486       ],
    487     },
    488   }, 'targetSets');
    489   await wrapper.findComponent({ name: 'target-set-selector' }).setValue('B', 'selectedTargetSet');
    490   await wrapper.find('select[aria-label="Workout name customization"]').setValue('true');
    491   await wrapper.find('select[aria-label="Prediction model"]').setValue('CameronModel');
    492   await wrapper.findComponent({ name: 'decimal-input' }).setValue(1.3);
    493 
    494   // Assert correct update events emitted
    495   expect(wrapper.emitted()['update:globalOptions']).to.deep.equal([
    496     [{
    497       defaultUnitSystem: 'imperial',
    498       racePredictionOptions: {
    499         model: 'AverageModel',
    500         riegelExponent: 1.06,
    501       },
    502     }],
    503     [{
    504       defaultUnitSystem: 'imperial',
    505       racePredictionOptions: {
    506         model: 'CameronModel',
    507         riegelExponent: 1.06,
    508       },
    509     }],
    510     [{
    511       defaultUnitSystem: 'imperial',
    512       racePredictionOptions: {
    513         model: 'CameronModel',
    514         riegelExponent: 1.3,
    515       },
    516     }],
    517   ]);
    518   expect(wrapper.emitted()['update:targetSets']).to.deep.equal([[{
    519     'A': {
    520       name: '1st target set v2',
    521       targets: [
    522         { type: 'distance', distanceValue: 1, distanceUnit: 'miles' },
    523         { type: 'distance', distanceValue: 2, distanceUnit: 'miles' },
    524         { type: 'distance', distanceValue: 3, distanceUnit: 'miles' },
    525       ],
    526     },
    527     'B': {
    528       name: '2nd target set',
    529       targets: [
    530         { type: 'distance', distanceValue: 1, distanceUnit: 'kilometers' },
    531         { type: 'distance', distanceValue: 5, distanceUnit: 'kilometers' },
    532         { type: 'distance', distanceValue: 10, distanceUnit: 'kilometers' },
    533       ],
    534     },
    535   }]]);
    536   expect(wrapper.emitted()['update:options']).to.deep.equal([
    537     [{
    538       customTargetNames: false,
    539         input: {
    540           distanceValue: 5,
    541           distanceUnit: 'kilometers',
    542           time: 1200,
    543         },
    544       selectedTargetSet: 'B',
    545     }],
    546     [{
    547       customTargetNames: true,
    548         input: {
    549           distanceValue: 5,
    550           distanceUnit: 'kilometers',
    551           time: 1200,
    552         },
    553       selectedTargetSet: 'B',
    554     }],
    555   ]);
    556 });