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