github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/frontend-service/src/ui/components/SideBar/SideBar.test.tsx (about) 1 /*This file is part of kuberpult. 2 3 Kuberpult is free software: you can redistribute it and/or modify 4 it under the terms of the Expat(MIT) License as published by 5 the Free Software Foundation. 6 7 Kuberpult is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 MIT License for more details. 11 12 You should have received a copy of the MIT License 13 along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>. 14 15 Copyright 2023 freiheit.com*/ 16 import { act, render, renderHook } from '@testing-library/react'; 17 import { TopAppBar } from '../TopAppBar/TopAppBar'; 18 import { MemoryRouter } from 'react-router-dom'; 19 import { BatchAction, LockBehavior } from '../../../api/api'; 20 import { 21 addAction, 22 deleteAction, 23 useActions, 24 updateActions, 25 deleteAllActions, 26 appendAction, 27 DisplayLock, 28 } from '../../utils/store'; 29 import { ActionDetails, ActionTypes, getActionDetails, SideBar } from './SideBar'; 30 import { elementQuerySelectorSafe } from '../../../setupTests'; 31 32 describe('Show and Hide Sidebar', () => { 33 interface dataT { 34 name: string; 35 expect: (container: HTMLElement) => HTMLElement | void; 36 } 37 38 const data: dataT[] = [ 39 { 40 name: 'Sidebar is hidden', 41 expect: (container) => 42 expect(container.getElementsByClassName('mdc-drawer-sidebar--hidden')[0]).toBeTruthy(), 43 }, 44 { 45 name: 'Sidebar is displayed', 46 expect: (container) => { 47 const result = elementQuerySelectorSafe(container, '.mdc-show-button'); 48 act(() => { 49 result.click(); 50 }); 51 expect(container.getElementsByClassName('mdc-drawer-sidebar--displayed')[0]).toBeTruthy(); 52 }, 53 }, 54 ]; 55 56 const getNode = (overrides?: {}): JSX.Element => { 57 // given 58 const defaultProps: any = { 59 children: null, 60 }; 61 return ( 62 <MemoryRouter> 63 <TopAppBar {...defaultProps} {...overrides} />{' '} 64 </MemoryRouter> 65 ); 66 }; 67 const getWrapper = (overrides?: {}) => render(getNode(overrides)); 68 69 describe.each(data)(`SideBar functionality`, (testcase) => { 70 it(testcase.name, () => { 71 // when 72 const { container } = getWrapper({}); 73 // then 74 testcase.expect(container); 75 }); 76 }); 77 }); 78 79 describe('Sidebar shows list of actions', () => { 80 interface dataT { 81 name: string; 82 actions: BatchAction[]; 83 expectedNumOfActions: number; 84 } 85 86 const data: dataT[] = [ 87 { 88 name: '2 results', 89 actions: [ 90 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 91 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 92 ], 93 expectedNumOfActions: 2, 94 }, 95 { 96 name: '1 results, repeated', 97 actions: [ 98 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 99 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 100 ], 101 expectedNumOfActions: 1, 102 }, 103 { 104 name: '3 results', 105 actions: [ 106 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 107 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 108 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 109 ], 110 expectedNumOfActions: 3, 111 }, 112 { 113 name: '2 results, repeated', 114 actions: [ 115 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 116 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 117 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 118 ], 119 expectedNumOfActions: 2, 120 }, 121 { 122 name: '0 results', 123 actions: [], 124 expectedNumOfActions: 0, 125 }, 126 ]; 127 128 const getNode = (overrides?: {}): JSX.Element | any => { 129 // given 130 const defaultProps: any = { 131 children: null, 132 }; 133 return ( 134 <MemoryRouter> 135 <TopAppBar {...defaultProps} {...overrides} />{' '} 136 </MemoryRouter> 137 ); 138 }; 139 const getWrapper = (overrides?: {}) => render(getNode(overrides)); 140 141 describe.each(data)('', (testcase) => { 142 it(testcase.name, () => { 143 // given 144 updateActions(testcase.actions); 145 // when 146 const { container } = getWrapper({}); 147 const result = elementQuerySelectorSafe(container, '.mdc-show-button'); 148 act(() => { 149 result.click(); 150 }); 151 // then 152 expect(container.getElementsByClassName('mdc-drawer-sidebar-list')[0].children).toHaveLength( 153 testcase.expectedNumOfActions 154 ); 155 }); 156 }); 157 }); 158 159 describe('Sidebar test deletebutton', () => { 160 interface dataT { 161 name: string; 162 actions: BatchAction[]; 163 expectedNumOfActions: number; 164 } 165 166 const data: dataT[] = [ 167 { 168 name: '2 results', 169 actions: [ 170 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 171 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 172 ], 173 expectedNumOfActions: 1, 174 }, 175 { 176 name: '3 results', 177 actions: [ 178 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 179 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 180 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 181 ], 182 expectedNumOfActions: 2, 183 }, 184 { 185 name: '0 results', 186 actions: [], 187 expectedNumOfActions: 0, 188 }, 189 ]; 190 191 const getNode = (overrides?: {}): JSX.Element | any => { 192 // given 193 const defaultProps: any = { 194 children: null, 195 }; 196 return ( 197 <MemoryRouter> 198 <TopAppBar {...defaultProps} {...overrides} />{' '} 199 </MemoryRouter> 200 ); 201 }; 202 const getWrapper = (overrides?: {}) => render(getNode(overrides)); 203 204 describe.each(data)('', (testcase) => { 205 it(testcase.name, () => { 206 // given 207 updateActions(testcase.actions); 208 // when 209 const { container } = getWrapper({}); 210 const result = elementQuerySelectorSafe(container, '.mdc-show-button'); 211 act(() => { 212 result.click(); 213 }); 214 const svg = container.getElementsByClassName('mdc-drawer-sidebar-list-item-delete-icon')[0]; 215 if (svg) { 216 const button = svg.parentElement; 217 if (button) button.click(); 218 } 219 // then 220 expect(container.getElementsByClassName('mdc-drawer-sidebar-list')[0].children).toHaveLength( 221 testcase.expectedNumOfActions 222 ); 223 }); 224 }); 225 }); 226 227 describe('Action Store functionality', () => { 228 interface dataT { 229 name: string; 230 actions: BatchAction[]; 231 deleteActions?: BatchAction[]; 232 expectedActions: BatchAction[]; 233 } 234 235 const dataGetSet: dataT[] = [ 236 { 237 name: '1 action', 238 actions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 239 expectedActions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 240 }, 241 { 242 name: 'Empty action store', 243 actions: [], 244 expectedActions: [], 245 }, 246 { 247 name: '2 different type of actions', 248 actions: [ 249 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 250 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 251 ], 252 expectedActions: [ 253 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 254 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 255 ], 256 }, 257 { 258 name: '2 actions of the same type', 259 actions: [ 260 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 261 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 262 ], 263 expectedActions: [ 264 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 265 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 266 ], 267 }, 268 ]; 269 270 describe.each(dataGetSet)('Test getting actions from the store and setting the store from an array', (testcase) => { 271 it(testcase.name, () => { 272 // given 273 updateActions(testcase.actions); 274 // when 275 const actions = renderHook(() => useActions()).result.current; 276 // then 277 expect(actions).toStrictEqual(testcase.expectedActions); 278 }); 279 }); 280 281 const dataAdding: dataT[] = [ 282 { 283 name: '1 action', 284 actions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 285 expectedActions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 286 }, 287 { 288 name: 'Empty action store', 289 actions: [], 290 expectedActions: [], 291 }, 292 { 293 name: '2 different type of actions', 294 actions: [ 295 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 296 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 297 ], 298 expectedActions: [ 299 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 300 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 301 ], 302 }, 303 { 304 name: '2 actions of the same type', 305 actions: [ 306 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 307 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 308 ], 309 expectedActions: [ 310 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 311 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 312 ], 313 }, 314 ]; 315 316 describe.each(dataAdding)('Test adding actions to the store', (testcase) => { 317 it(testcase.name, () => { 318 // given 319 deleteAllActions(); 320 testcase.actions.forEach((action) => { 321 addAction(action); 322 }); 323 // when 324 const actions = renderHook(() => useActions()).result.current; 325 // then 326 expect(actions).toStrictEqual(testcase.expectedActions); 327 }); 328 }); 329 330 const dataDeleting: dataT[] = [ 331 { 332 name: 'delete 1 action - 0 remain', 333 actions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 334 deleteActions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 335 expectedActions: [], 336 }, 337 { 338 name: 'delete 1 action (different action type, same app) - 1 remains', 339 actions: [ 340 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 341 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 342 ], 343 deleteActions: [{ action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }], 344 expectedActions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 345 }, 346 { 347 name: 'delete 1 action (same action type, different app) - 1 remains', 348 actions: [ 349 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 350 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 351 ], 352 deleteActions: [{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }], 353 expectedActions: [{ action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }], 354 }, 355 { 356 name: 'delete 1 action from empty array - 0 remain', 357 actions: [], 358 deleteActions: [{ action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }], 359 expectedActions: [], 360 }, 361 { 362 name: 'delete 2 actions - 1 remain', 363 actions: [ 364 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 365 { action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }, 366 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 367 ], 368 deleteActions: [ 369 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 370 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 371 ], 372 expectedActions: [{ action: { $case: 'undeploy', undeploy: { application: 'auth-service' } } }], 373 }, 374 ]; 375 376 describe.each(dataDeleting)('Test deleting actions', (testcase) => { 377 it(testcase.name, () => { 378 // given 379 updateActions(testcase.actions); 380 // when 381 testcase.deleteActions?.map((action) => deleteAction(action)); 382 const actions = renderHook(() => useActions()).result.current; 383 // then 384 expect(actions).toStrictEqual(testcase.expectedActions); 385 }); 386 }); 387 }); 388 389 describe('Action details', () => { 390 interface dataT { 391 name: string; 392 action: BatchAction; 393 envLocks?: DisplayLock[]; 394 appLocks?: DisplayLock[]; 395 expectedDetails: ActionDetails; 396 } 397 const data: dataT[] = [ 398 { 399 name: 'test createEnvironmentLock action', 400 action: { 401 action: { 402 $case: 'createEnvironmentLock', 403 createEnvironmentLock: { environment: 'foo', lockId: 'ui-v2-1337', message: 'bar' }, 404 }, 405 }, 406 expectedDetails: { 407 type: ActionTypes.CreateEnvironmentLock, 408 name: 'Create Env Lock', 409 dialogTitle: 'Are you sure you want to add this environment lock?', 410 tooltip: 411 'An environment lock will prevent automated process from changing the deployed version - note that kuberpult users can still deploy despite locks.', 412 summary: 'Create new environment lock on foo', 413 environment: 'foo', 414 }, 415 }, 416 { 417 name: 'test deleteEnvironmentLock action', 418 action: { 419 action: { 420 $case: 'deleteEnvironmentLock', 421 deleteEnvironmentLock: { environment: 'foo', lockId: 'ui-v2-1337' }, 422 }, 423 }, 424 envLocks: [ 425 { 426 lockId: 'ui-v2-1337', 427 environment: 'foo', 428 message: 'bar', 429 }, 430 ], 431 expectedDetails: { 432 type: ActionTypes.DeleteEnvironmentLock, 433 name: 'Delete Env Lock', 434 dialogTitle: 'Are you sure you want to delete this environment lock?', 435 summary: 'Delete environment lock on foo with the message: "bar"', 436 tooltip: 'This will only remove the lock, it will not automatically deploy anything.', 437 environment: 'foo', 438 lockId: 'ui-v2-1337', 439 lockMessage: 'bar', 440 }, 441 }, 442 { 443 name: 'test createEnvironmentApplicationLock action', 444 action: { 445 action: { 446 $case: 'createEnvironmentApplicationLock', 447 createEnvironmentApplicationLock: { 448 environment: 'foo', 449 application: 'bread', 450 lockId: 'ui-v2-1337', 451 message: 'bar', 452 }, 453 }, 454 }, 455 expectedDetails: { 456 type: ActionTypes.CreateApplicationLock, 457 name: 'Create App Lock', 458 dialogTitle: 'Are you sure you want to add this application lock?', 459 summary: 'Create new application lock for "bread" on foo', 460 tooltip: 461 'An app lock will prevent automated process from changing the deployed version - note that kuberpult users can still deploy despite locks.', 462 environment: 'foo', 463 application: 'bread', 464 }, 465 }, 466 { 467 name: 'test deleteEnvironmentApplicationLock action', 468 action: { 469 action: { 470 $case: 'deleteEnvironmentApplicationLock', 471 deleteEnvironmentApplicationLock: { environment: 'foo', application: 'bar', lockId: 'ui-v2-1337' }, 472 }, 473 }, 474 appLocks: [ 475 { 476 lockId: 'ui-v2-1337', 477 environment: 'foo', 478 message: 'bar', 479 application: 'bar', 480 }, 481 ], 482 expectedDetails: { 483 type: ActionTypes.DeleteApplicationLock, 484 name: 'Delete App Lock', 485 dialogTitle: 'Are you sure you want to delete this application lock?', 486 summary: 'Delete application lock for "bar" on foo with the message: "bar"', 487 tooltip: 'This will only remove the lock, it will not automatically deploy anything.', 488 environment: 'foo', 489 application: 'bar', 490 lockId: 'ui-v2-1337', 491 lockMessage: 'bar', 492 }, 493 }, 494 { 495 name: 'test deploy action', 496 action: { 497 action: { 498 $case: 'deploy', 499 deploy: { 500 environment: 'foo', 501 application: 'bread', 502 version: 1337, 503 ignoreAllLocks: false, 504 lockBehavior: LockBehavior.IGNORE, 505 }, 506 }, 507 }, 508 expectedDetails: { 509 type: ActionTypes.Deploy, 510 name: 'Deploy', 511 dialogTitle: 'Please be aware:', 512 summary: 'Deploy version 1337 of "bread" to foo', 513 tooltip: '', 514 environment: 'foo', 515 application: 'bread', 516 version: 1337, 517 }, 518 }, 519 { 520 name: 'test prepareUndeploy action', 521 action: { 522 action: { 523 $case: 'prepareUndeploy', 524 prepareUndeploy: { 525 application: 'foo', 526 }, 527 }, 528 }, 529 expectedDetails: { 530 type: ActionTypes.PrepareUndeploy, 531 name: 'Prepare Undeploy', 532 dialogTitle: 'Are you sure you want to start undeploy?', 533 tooltip: 534 'The new version will go through the same cycle as any other versions' + 535 ' (e.g. development->staging->production). ' + 536 'The behavior is similar to any other version that is created normally.', 537 summary: 'Prepare undeploy version for Application "foo"', 538 application: 'foo', 539 }, 540 }, 541 { 542 name: 'test undeploy action', 543 action: { 544 action: { 545 $case: 'undeploy', 546 undeploy: { 547 application: 'foo', 548 }, 549 }, 550 }, 551 expectedDetails: { 552 type: ActionTypes.Undeploy, 553 name: 'Undeploy', 554 dialogTitle: 'Are you sure you want to undeploy this application?', 555 tooltip: 'This application will be deleted permanently', 556 summary: 'Undeploy and delete Application "foo"', 557 application: 'foo', 558 }, 559 }, 560 { 561 name: 'test delete env from app action', 562 action: { 563 action: { 564 $case: 'deleteEnvFromApp', 565 deleteEnvFromApp: { 566 environment: 'dev', 567 application: 'foo', 568 }, 569 }, 570 }, 571 expectedDetails: { 572 type: ActionTypes.DeleteEnvFromApp, 573 name: 'Delete an Environment from App', 574 dialogTitle: 'Are you sure you want to delete environments from this application?', 575 tooltip: 'These environments will be deleted permanently from this application', 576 summary: 'Delete environment "dev" from application "foo"', 577 application: 'foo', 578 }, 579 }, 580 { 581 name: 'test releaseTrain action', 582 action: { 583 action: { 584 $case: 'releaseTrain', 585 releaseTrain: { 586 target: 'dev', 587 team: '', 588 commitHash: '', 589 }, 590 }, 591 }, 592 expectedDetails: { 593 type: ActionTypes.ReleaseTrain, 594 name: 'Release Train', 595 dialogTitle: 'Are you sure you want to run a Release Train', 596 summary: 'Run release train to environment dev', 597 tooltip: '', 598 environment: 'dev', 599 }, 600 }, 601 ]; 602 603 describe.each(data)('Test getActionDetails function', (testcase) => { 604 it(testcase.name, () => { 605 const envLocks = testcase.envLocks || []; 606 const appLocks = testcase.appLocks || []; 607 const obtainedDetails = renderHook(() => getActionDetails(testcase.action, appLocks, envLocks)).result 608 .current; 609 expect(obtainedDetails).toStrictEqual(testcase.expectedDetails); 610 }); 611 }); 612 613 describe('Sidebar shows the number of planned actions', () => { 614 interface dataT { 615 name: string; 616 actions: BatchAction[]; 617 expectedTitle: string; 618 } 619 620 const data: dataT[] = [ 621 { 622 name: '2 results', 623 actions: [ 624 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 625 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 626 ], 627 expectedTitle: 'Planned Actions (2)', 628 }, 629 { 630 name: '1 results, repeated', 631 actions: [ 632 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 633 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 634 ], 635 expectedTitle: 'Planned Actions (1)', 636 }, 637 { 638 name: '0 results', 639 actions: [], 640 expectedTitle: 'Planned Actions', 641 }, 642 ]; 643 644 const getNode = (overrides?: {}): JSX.Element | any => { 645 // given 646 const defaultProps: any = { 647 children: null, 648 }; 649 return ( 650 <MemoryRouter> 651 <SideBar {...defaultProps} {...overrides} /> 652 </MemoryRouter> 653 ); 654 }; 655 const getWrapper = (overrides?: {}) => render(getNode(overrides)); 656 657 describe.each(data)('', (testcase) => { 658 it(testcase.name, () => { 659 updateActions(testcase.actions); 660 const { container } = getWrapper({}); 661 expect(container.getElementsByClassName('mdc-drawer-sidebar-header-title')[0].textContent).toBe( 662 testcase.expectedTitle 663 ); 664 }); 665 }); 666 }); 667 describe('Sidebar shows updates number of planned actions', () => { 668 interface dataT { 669 name: string; 670 actions: BatchAction[]; 671 expectedTitle: string; 672 } 673 674 const data: dataT[] = [ 675 { 676 name: 'add 2 actions', 677 actions: [ 678 { action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }, 679 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }, 680 ], 681 expectedTitle: 'Planned Actions (3)', 682 }, 683 { 684 name: 'Add another action', 685 actions: [ 686 { 687 action: { 688 $case: 'deploy', 689 deploy: { 690 environment: 'foo', 691 application: 'bread', 692 version: 1337, 693 ignoreAllLocks: false, 694 lockBehavior: LockBehavior.IGNORE, 695 }, 696 }, 697 }, 698 ], 699 expectedTitle: 'Planned Actions (4)', 700 }, 701 { 702 name: 'Add 2 more actions actions', 703 actions: [ 704 { action: { $case: 'undeploy', undeploy: { application: 'test2' } } }, 705 { action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'test2' } } }, 706 ], 707 expectedTitle: 'Planned Actions (6)', 708 }, 709 ]; 710 711 const getNode = (overrides?: {}): JSX.Element | any => { 712 // given 713 const defaultProps: any = { 714 children: null, 715 }; 716 return ( 717 <MemoryRouter> 718 <SideBar {...defaultProps} {...overrides} /> 719 </MemoryRouter> 720 ); 721 }; 722 const getWrapper = (overrides?: {}) => render(getNode(overrides)); 723 it('Create an action initially', () => { 724 updateActions([{ action: { $case: 'undeploy', undeploy: { application: 'test' } } }]); 725 const { container } = getWrapper({}); 726 expect(container.getElementsByClassName('mdc-drawer-sidebar-header-title')[0].textContent).toBe( 727 'Planned Actions (1)' 728 ); 729 }); 730 describe.each(data)('', (testcase) => { 731 it(testcase.name, () => { 732 appendAction(testcase.actions); 733 const { container } = getWrapper({}); 734 expect(container.getElementsByClassName('mdc-drawer-sidebar-header-title')[0].textContent).toBe( 735 testcase.expectedTitle 736 ); 737 }); 738 }); 739 describe('Deleting an action from the cart', () => { 740 it('Test deleting an an action', () => { 741 updateActions([{ action: { $case: 'undeploy', undeploy: { application: 'nmww' } } }]); 742 appendAction([{ action: { $case: 'prepareUndeploy', prepareUndeploy: { application: 'nmww' } } }]); 743 // Here we expect the value to be Planned Actions (1) 744 const expected = 'Planned Actions (1)'; 745 const { container } = getWrapper({}); 746 const svg = container.getElementsByClassName('mdc-drawer-sidebar-list-item-delete-icon')[0]; 747 if (svg) { 748 const button = svg.parentElement; 749 if (button) button.click(); 750 } 751 expect(container.getElementsByClassName('mdc-drawer-sidebar-header-title')[0].textContent).toBe( 752 expected 753 ); 754 }); 755 }); 756 }); 757 });