TargetEditor.spec.js (21354B)
1 import { test, expect } from 'vitest'; 2 import { shallowMount } from '@vue/test-utils'; 3 import TargetEditor from '@/components/TargetEditor.vue'; 4 5 test('should correctly render standard target set', async () => { 6 // Initialize component 7 const wrapper = shallowMount(TargetEditor, { 8 propsData: { 9 modelValue: { 10 name: 'My target set', 11 targets: [ 12 { distanceUnit: 'kilometers', distanceValue: 1.61, type: 'distance' }, 13 { distanceUnit: 'miles', distanceValue: 3.11, type: 'distance' }, 14 { time: 600, type: 'time' }, 15 ], 16 }, 17 setType: 'standard', 18 customWorkoutNames: true, // name input should not be rendered 19 }, 20 }); 21 22 // Assert target set correctly rendered 23 expect(wrapper.find('input').element.value).to.equal('My target set'); 24 const rows = wrapper.findAll('tbody tr'); 25 expect(rows[0].findAll('input').length).to.equal(0); 26 expect(rows[0].findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(1.61); 27 expect(rows[0].find('select').element.value).to.equal('kilometers'); 28 expect(rows[1].findAll('input').length).to.equal(0); 29 expect(rows[1].findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(3.11); 30 expect(rows[1].find('select').element.value).to.equal('miles'); 31 expect(rows[2].findAll('input').length).to.equal(0); 32 expect(rows[2].findComponent({ name: 'time-input' }).vm.modelValue).to.equal(600); 33 expect(rows.length).to.equal(3); 34 }); 35 36 test('should correctly render split target set', async () => { 37 // Initialize component 38 const wrapper = shallowMount(TargetEditor, { 39 propsData: { 40 modelValue: { 41 name: 'My target set', 42 targets: [ 43 { distanceUnit: 'kilometers', distanceValue: 1.61, type: 'distance' }, 44 { distanceUnit: 'miles', distanceValue: 3.11, type: 'distance' }, 45 ], 46 }, 47 setType: 'split', 48 }, 49 }); 50 51 // Assert target set correctly rendered 52 expect(wrapper.find('input').element.value).to.equal('My target set'); 53 const rows = wrapper.findAll('tbody tr'); 54 expect(rows[0].findAll('input').length).to.equal(0); 55 expect(rows[0].findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(1.61); 56 expect(rows[0].find('select').element.value).to.equal('kilometers'); 57 expect(rows[1].findAll('input').length).to.equal(0); 58 expect(rows[1].findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(3.11); 59 expect(rows[1].find('select').element.value).to.equal('miles'); 60 expect(rows.length).to.equal(2); 61 }); 62 63 test('should correctly render workout target set without custom names', async () => { 64 // Initialize component 65 const wrapper = shallowMount(TargetEditor, { 66 propsData: { 67 modelValue: { 68 name: 'My target set', 69 targets: [ 70 { 71 distanceUnit: 'miles', distanceValue: 2, 72 splitUnit: 'meters', splitValue: 400, 73 type: 'distance', 74 }, 75 { 76 time: 6000, 77 splitUnit: 'kilometers', splitValue: 2, 78 type: 'time', 79 }, 80 { 81 distanceUnit: 'kilometers', distanceValue: 5, 82 splitUnit: 'miles', splitValue: 1, 83 type: 'distance' 84 }, 85 ], 86 }, 87 setType: 'workout', 88 }, 89 }); 90 91 // Assert target set correctly rendered 92 expect(wrapper.find('input').element.value).to.equal('My target set'); 93 const rows = wrapper.findAll('tbody tr'); 94 expect(rows[0].findAll('input').length).to.equal(0); 95 expect(rows[0].findAllComponents({ name: 'decimal-input' })[0].vm.modelValue).to.equal(400); 96 expect(rows[0].findAll('select')[0].element.value).to.equal('meters'); 97 expect(rows[0].findAllComponents({ name: 'decimal-input' })[1].vm.modelValue).to.equal(2); 98 expect(rows[0].findAll('select')[1].element.value).to.equal('miles'); 99 expect(rows[1].findAll('input').length).to.equal(0); 100 expect(rows[1].findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(2); 101 expect(rows[1].find('select').element.value).to.equal('kilometers'); 102 expect(rows[1].findComponent({ name: 'time-input' }).vm.modelValue).to.equal(6000); 103 expect(rows[2].findAll('input').length).to.equal(0); 104 expect(rows[2].findAllComponents({ name: 'decimal-input' })[0].vm.modelValue).to.equal(1); 105 expect(rows[2].findAll('select')[0].element.value).to.equal('miles'); 106 expect(rows[2].findAllComponents({ name: 'decimal-input' })[1].vm.modelValue).to.equal(5); 107 expect(rows[2].findAll('select')[1].element.value).to.equal('kilometers'); 108 expect(rows.length).to.equal(3); 109 }); 110 111 test('should correctly render workout target set with custom names', async () => { 112 // Initialize component 113 const wrapper = shallowMount(TargetEditor, { 114 propsData: { 115 modelValue: { 116 name: 'My target set', 117 targets: [ 118 { 119 // customName is undefined 120 distanceUnit: 'miles', distanceValue: 2, 121 splitUnit: 'meters', splitValue: 400, 122 type: 'distance', 123 }, 124 { 125 customName: '', 126 time: 6000, 127 splitUnit: 'kilometers', splitValue: 2, 128 type: 'time', 129 }, 130 { 131 customName: 'my custom name', 132 distanceUnit: 'kilometers', distanceValue: 5, 133 splitUnit: 'miles', splitValue: 1, 134 type: 'distance' 135 }, 136 ], 137 }, 138 setType: 'workout', 139 customWorkoutNames: true, 140 }, 141 }); 142 143 // Assert target set correctly rendered 144 expect(wrapper.find('input').element.value).to.equal('My target set'); 145 const rows = wrapper.findAll('tbody tr'); 146 expect(rows[0].find('input').element.value).to.equal(''); 147 expect(rows[0].find('input').element.placeholder).to.equal('400 m @ 2 mi'); 148 expect(rows[0].findAllComponents({ name: 'decimal-input' })[0].vm.modelValue).to.equal(400); 149 expect(rows[0].findAll('select')[0].element.value).to.equal('meters'); 150 expect(rows[0].findAllComponents({ name: 'decimal-input' })[1].vm.modelValue).to.equal(2); 151 expect(rows[0].findAll('select')[1].element.value).to.equal('miles'); 152 expect(rows[1].find('input').element.value).to.equal(''); 153 expect(rows[1].find('input').element.placeholder).to.equal('2 km @ 1:40:00'); 154 expect(rows[1].findComponent({ name: 'decimal-input' }).vm.modelValue).to.equal(2); 155 expect(rows[1].find('select').element.value).to.equal('kilometers'); 156 expect(rows[1].findComponent({ name: 'time-input' }).vm.modelValue).to.equal(6000); 157 expect(rows[2].find('input').element.value).to.equal('my custom name'); 158 expect(rows[2].find('input').element.placeholder).to.equal('1 mi @ 5 km'); 159 expect(rows[2].findAllComponents({ name: 'decimal-input' })[0].vm.modelValue).to.equal(1); 160 expect(rows[2].findAll('select')[0].element.value).to.equal('miles'); 161 expect(rows[2].findAllComponents({ name: 'decimal-input' })[1].vm.modelValue).to.equal(5); 162 expect(rows[2].findAll('select')[1].element.value).to.equal('kilometers'); 163 expect(rows.length).to.equal(3); 164 }); 165 166 test('revert button should emit revert event', async () => { 167 // Initialize component 168 const wrapper = shallowMount(TargetEditor, { 169 propsData: { 170 modelValue: { 171 name: 'My target set', 172 targets: [], 173 }, 174 }, 175 }); 176 177 // Click revert button 178 await wrapper.find('button[title="Revert target set"]').trigger('click'); 179 180 // Assert revert event was emitted 181 expect(wrapper.emitted().revert.length).to.equal(1); 182 }); 183 184 test('delete button should emit revert event', async () => { 185 // Initialize component 186 const wrapper = shallowMount(TargetEditor, { 187 propsData: { 188 modelValue: { 189 name: 'My target set', 190 targets: [], 191 }, 192 isCustomSet: true, 193 }, 194 }); 195 196 // Click delete button 197 await wrapper.find('button[title="Delete target set"]').trigger('click'); 198 199 // Assert revert event was emitted 200 expect(wrapper.emitted().revert.length).to.equal(1); 201 }); 202 203 test('close button should emit close event', async () => { 204 // Initialize component 205 const wrapper = shallowMount(TargetEditor, { 206 propsData: { 207 modelValue: { 208 name: 'My target set', 209 targets: [], 210 }, 211 }, 212 }); 213 214 // Call close method 215 await wrapper.find('button[title="Close"]').trigger('click'); 216 217 // Assert close event was emitted 218 expect(wrapper.emitted().close.length).to.equal(1); 219 }); 220 221 test('add distance target button should correctly add standard imperial distance target', async () => { 222 // Initialize component 223 const wrapper = shallowMount(TargetEditor, { 224 propsData: { 225 modelValue: { 226 name: 'My target set', 227 targets: [ 228 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 229 { time: 0, type: 'time' }, 230 ], 231 }, 232 setType: 'standard', 233 defaultUnitSystem: 'imperial', 234 }, 235 }); 236 237 // Add distance target 238 await wrapper.find('button[title="Add distance target"]').trigger('click'); 239 240 // Assert input event was emitted 241 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 242 [{ 243 name: 'My target set', 244 targets: [ 245 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 246 { time: 0, type: 'time' }, 247 { distanceUnit: 'miles', distanceValue: 1, type: 'distance'}, 248 ], 249 }], 250 ]); 251 }); 252 253 test('add distance target button should correctly add standard metric distance target', async () => { 254 // Initialize component 255 const wrapper = shallowMount(TargetEditor, { 256 propsData: { 257 modelValue: { 258 name: 'My target set', 259 targets: [ 260 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 261 { time: 0, type: 'time' }, 262 ], 263 }, 264 setType: 'standard', 265 defaultUnitSystem: 'metric', 266 }, 267 }); 268 269 // Add distance target 270 await wrapper.find('button[title="Add distance target"]').trigger('click'); 271 272 // Assert input event was emitted 273 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 274 [{ 275 name: 'My target set', 276 targets: [ 277 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 278 { time: 0, type: 'time' }, 279 { distanceUnit: 'kilometers', distanceValue: 1, type: 'distance'}, 280 ], 281 }], 282 ]); 283 }); 284 285 test('add distance target button should correctly add split imperial distance target', async () => { 286 // Initialize component 287 const wrapper = shallowMount(TargetEditor, { 288 propsData: { 289 modelValue: { 290 name: 'My target set', 291 targets: [ 292 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 293 ], 294 }, 295 setType: 'split', 296 defaultUnitSystem: 'imperial', 297 }, 298 }); 299 300 // Add distance target 301 await wrapper.find('button[title="Add distance target"]').trigger('click'); 302 303 // Assert input event was emitted 304 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 305 [{ 306 name: 'My target set', 307 targets: [ 308 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 309 { distanceUnit: 'miles', distanceValue: 1, type: 'distance'}, 310 ], 311 }], 312 ]); 313 }); 314 315 test('add distance target button should correctly add split metric distance target', async () => { 316 // Initialize component 317 const wrapper = shallowMount(TargetEditor, { 318 propsData: { 319 modelValue: { 320 name: 'My target set', 321 targets: [ 322 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 323 ], 324 }, 325 setType: 'split', 326 defaultUnitSystem: 'metric', 327 }, 328 }); 329 330 // Add distance target 331 await wrapper.find('button[title="Add distance target"]').trigger('click'); 332 333 // Assert input event was emitted 334 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 335 [{ 336 name: 'My target set', 337 targets: [ 338 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 339 { distanceUnit: 'kilometers', distanceValue: 1, type: 'distance'}, 340 ], 341 }], 342 ]); 343 }); 344 345 test('add distance target button should correctly add workout imperial distance target', async () => { 346 // Initialize component 347 const wrapper = shallowMount(TargetEditor, { 348 propsData: { 349 modelValue: { 350 name: 'My target set', 351 targets: [ 352 { 353 distanceUnit: 'miles', distanceValue: 2, 354 splitUnit: 'meters', splitValue: 400, 355 type: 'distance', 356 }, 357 { 358 time: 6000, 359 splitUnit: 'kilometers', splitValue: 2, 360 type: 'time', 361 }, 362 ], 363 }, 364 setType: 'workout', 365 defaultUnitSystem: 'imperial', 366 }, 367 }); 368 369 // Add distance target 370 await wrapper.find('button[title="Add distance target"]').trigger('click'); 371 372 // Assert input event was emitted 373 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 374 [{ 375 name: 'My target set', 376 targets: [ 377 { 378 distanceUnit: 'miles', distanceValue: 2, 379 splitUnit: 'meters', splitValue: 400, 380 type: 'distance', 381 }, 382 { 383 time: 6000, 384 splitUnit: 'kilometers', splitValue: 2, 385 type: 'time', 386 }, 387 { 388 distanceUnit: 'miles', distanceValue: 1, 389 splitUnit: 'miles', splitValue: 1, 390 type: 'distance' 391 }, 392 ], 393 }], 394 ]); 395 }); 396 397 test('add distance target button should correctly add workout metric distance target', async () => { 398 // Initialize component 399 const wrapper = shallowMount(TargetEditor, { 400 propsData: { 401 modelValue: { 402 name: 'My target set', 403 targets: [ 404 { 405 distanceUnit: 'miles', distanceValue: 2, 406 splitUnit: 'meters', splitValue: 400, 407 type: 'distance', 408 }, 409 { 410 time: 6000, 411 splitUnit: 'kilometers', splitValue: 2, 412 type: 'time', 413 }, 414 ], 415 }, 416 setType: 'workout', 417 defaultUnitSystem: 'metric', 418 }, 419 }); 420 421 // Add distance target 422 await wrapper.find('button[title="Add distance target"]').trigger('click'); 423 424 // Assert input event was emitted 425 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 426 [{ 427 name: 'My target set', 428 targets: [ 429 { 430 distanceUnit: 'miles', distanceValue: 2, 431 splitUnit: 'meters', splitValue: 400, 432 type: 'distance', 433 }, 434 { 435 time: 6000, 436 splitUnit: 'kilometers', splitValue: 2, 437 type: 'time', 438 }, 439 { 440 distanceUnit: 'kilometers', distanceValue: 1, 441 splitUnit: 'kilometers', splitValue: 1, 442 type: 'distance' 443 }, 444 ], 445 }], 446 ]); 447 }); 448 449 test('add time target button should correctly add standard time target', async () => { 450 // Initialize component 451 const wrapper = shallowMount(TargetEditor, { 452 propsData: { 453 modelValue: { 454 name: 'My target set', 455 targets: [ 456 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 457 { time: 0, type: 'time' }, 458 ], 459 }, 460 setType: 'standard', 461 }, 462 }); 463 464 // Add time target 465 await wrapper.find('button[title="Add time target"]').trigger('click'); 466 467 // Assert input event was emitted 468 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 469 [{ name: 'My target set', 470 targets: [ 471 { distanceUnit: 'miles', distanceValue: 0, type: 'distance' }, 472 { time: 0, type: 'time' }, 473 { time: 600, type: 'time' }, 474 ], 475 }], 476 ]); 477 }); 478 479 test('add time target button should be hidden for split target sets', async () => { 480 // Initialize component 481 const wrapper = shallowMount(TargetEditor, { 482 propsData: { 483 modelValue: { 484 name: 'My target set', 485 targets: [ 486 { distanceUnit: 'miles', distanceValue: 1, type: 'distance' }, 487 { distanceUnit: 'miles', distanceValue: 2, type: 'distance' }, 488 ], 489 }, 490 setType: 'split', 491 }, 492 }); 493 494 // Add time target 495 expect(wrapper.findAll('button[title="Add time target"]')).toHaveLength(0); 496 }); 497 498 test('add time target button should correctly add workout imperial time target', async () => { 499 // Initialize component 500 const wrapper = shallowMount(TargetEditor, { 501 propsData: { 502 modelValue: { 503 name: 'My target set', 504 targets: [ 505 { 506 distanceUnit: 'miles', distanceValue: 2, 507 splitUnit: 'meters', splitValue: 400, 508 type: 'distance', 509 }, 510 { 511 time: 6000, 512 splitUnit: 'kilometers', splitValue: 2, 513 type: 'time', 514 }, 515 ], 516 }, 517 setType: 'workout', 518 defaultUnitSystem: 'imperial', 519 }, 520 }); 521 522 // Add distance target 523 await wrapper.find('button[title="Add time target"]').trigger('click'); 524 525 // Assert input event was emitted 526 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 527 [{ 528 name: 'My target set', 529 targets: [ 530 { 531 distanceUnit: 'miles', distanceValue: 2, 532 splitUnit: 'meters', splitValue: 400, 533 type: 'distance', 534 }, 535 { 536 time: 6000, 537 splitUnit: 'kilometers', splitValue: 2, 538 type: 'time', 539 }, 540 { 541 time: 600, 542 splitUnit: 'miles', splitValue: 1, 543 type: 'time' 544 }, 545 ], 546 }], 547 ]); 548 }); 549 550 test('add time target button should correctly add workout metric time target', async () => { 551 // Initialize component 552 const wrapper = shallowMount(TargetEditor, { 553 propsData: { 554 modelValue: { 555 name: 'My target set', 556 targets: [ 557 { 558 distanceUnit: 'miles', distanceValue: 2, 559 splitUnit: 'meters', splitValue: 400, 560 type: 'distance', 561 }, 562 { 563 time: 6000, 564 splitUnit: 'kilometers', splitValue: 2, 565 type: 'time', 566 }, 567 ], 568 }, 569 setType: 'workout', 570 defaultUnitSystem: 'metric', 571 }, 572 }); 573 574 // Add distance target 575 await wrapper.find('button[title="Add time target"]').trigger('click'); 576 577 // Assert input event was emitted 578 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 579 [{ 580 name: 'My target set', 581 targets: [ 582 { 583 distanceUnit: 'miles', distanceValue: 2, 584 splitUnit: 'meters', splitValue: 400, 585 type: 'distance', 586 }, 587 { 588 time: 6000, 589 splitUnit: 'kilometers', splitValue: 2, 590 type: 'time', 591 }, 592 { 593 time: 600, 594 splitUnit: 'kilometers', splitValue: 1, 595 type: 'time' 596 }, 597 ], 598 }], 599 ]); 600 }); 601 602 test('should emit input event when targets are updated', async () => { 603 // Initialize component 604 const wrapper = shallowMount(TargetEditor, { 605 propsData: { 606 modelValue: { 607 name: 'My target set', 608 targets: [ 609 { distanceUnit: 'miles', distanceValue: 2, type: 'distance' }, 610 ], 611 }, 612 }, 613 }); 614 615 // Update distance value 616 await wrapper.findComponent({ name: 'decimal-input' }).setValue(3); 617 618 // Assert input event was emitted 619 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 620 [ 621 { 622 name: 'My target set', 623 targets: [ 624 { distanceUnit: 'miles', distanceValue: 3, type: 'distance' }, 625 ], 626 }, 627 ], 628 ]); 629 }); 630 631 test('should emit input event when target set name is updated', async () => { 632 // Initialize component 633 const wrapper = shallowMount(TargetEditor, { 634 propsData: { 635 modelValue: { 636 name: 'My target set', 637 targets: [ 638 { distanceUnit: 'miles', distanceValue: 2, type: 'distance' }, 639 ], 640 }, 641 }, 642 }); 643 644 // Update distance value 645 await wrapper.find('input').setValue('My target set #2'); 646 647 // Assert input event was emitted 648 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 649 [ 650 { 651 name: 'My target set #2', 652 targets: [ 653 { distanceUnit: 'miles', distanceValue: 2, type: 'distance' }, 654 ], 655 }, 656 ], 657 ]); 658 }); 659 660 test('removeTarget button should correctly remove target', async () => { 661 // Initialize component 662 const wrapper = shallowMount(TargetEditor, { 663 propsData: { 664 modelValue: { 665 name: 'My target set', 666 targets: [ 667 { distanceUnit: 'miles', distanceValue: 1, type: 'distance' }, 668 { distanceUnit: 'miles', distanceValue: 2, type: 'distance' }, 669 { distanceUnit: 'miles', distanceValue: 3, type: 'distance' }, 670 ], 671 }, 672 }, 673 }); 674 675 // Remove 2nd target 676 await wrapper.findAll('button[title="Remove target"]')[1].trigger('click'); 677 678 // Assert input event was emitted 679 expect(wrapper.emitted()['update:modelValue']).to.deep.equal([ 680 [{ 681 name: 'My target set', 682 targets: [ 683 { distanceUnit: 'miles', distanceValue: 1, type: 'distance' }, 684 { distanceUnit: 'miles', distanceValue: 3, type: 'distance' }, 685 ], 686 }], 687 ]); 688 }); 689 690 test('should display message when target set is empty', async () => { 691 // Initialize component 692 const wrapper = shallowMount(TargetEditor, { 693 propsData: { 694 modelValue: { 695 name: 'My target set', 696 targets: [], 697 }, 698 }, 699 }); 700 701 // Assert message correctly rendered 702 const rows = wrapper.findAll('tbody tr'); 703 expect(rows[0].text()).to.equal('There aren\'t any targets in this set yet.'); 704 expect(rows.length).to.equal(1); 705 });