github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/frontend-service/src/ui/components/CommitInfo/CommitInfo.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 { render } from '@testing-library/react';
    17  import { CommitInfo } from './CommitInfo';
    18  import { MemoryRouter } from 'react-router-dom';
    19  import { GetCommitInfoResponse, LockPreventedDeploymentEvent_LockType } from '../../../api/api';
    20  
    21  test('CommitInfo component does not render commit info when the response is undefined', () => {
    22      const { container } = render(
    23          <MemoryRouter>
    24              <CommitInfo commitInfo={undefined} />
    25          </MemoryRouter>
    26      );
    27      expect(container.textContent).toContain('Backend returned empty response');
    28  });
    29  
    30  test('CommitInfo component renders commit info when the response is valid', () => {
    31      type Table = {
    32          head: string[];
    33          // NOTE: newlines, if there are any, will effectively be removed, since they will be checked using .toHaveTextContent
    34          body: string[][];
    35      };
    36  
    37      type TestCase = {
    38          commitInfo: GetCommitInfoResponse;
    39          expectedTitle: string;
    40          expectedCommitDescriptionTable: Table;
    41          expectedEventsTable: Table;
    42      };
    43  
    44      const testCases: TestCase[] = [
    45          {
    46              commitInfo: {
    47                  commitHash: 'potato',
    48                  commitMessage: `tomato
    49                  
    50          Commit message body line 1
    51          Commit message body line 2`,
    52                  touchedApps: ['google', 'windows'],
    53                  nextCommitHash: '',
    54                  previousCommitHash: '',
    55                  events: [
    56                      {
    57                          uuid: '00000000-0000-0000-0000-000000000000',
    58                          createdAt: new Date('2024-02-09T09:46:00Z'),
    59                          eventType: {
    60                              $case: 'createReleaseEvent',
    61                              createReleaseEvent: {
    62                                  environmentNames: ['dev', 'staging'],
    63                              },
    64                          },
    65                      },
    66                      {
    67                          uuid: '00000000-0000-0000-0000-000000000001',
    68                          createdAt: new Date('2024-02-10T09:46:00Z'),
    69                          eventType: {
    70                              $case: 'deploymentEvent',
    71                              deploymentEvent: {
    72                                  application: 'app',
    73                                  targetEnvironment: 'dev',
    74                              },
    75                          },
    76                      },
    77                      {
    78                          uuid: '00000000-0000-0000-0000-000000000002',
    79                          createdAt: new Date('2024-02-11T09:46:00Z'),
    80                          eventType: {
    81                              $case: 'deploymentEvent',
    82                              deploymentEvent: {
    83                                  application: 'app',
    84                                  targetEnvironment: 'staging',
    85                                  releaseTrainSource: {
    86                                      upstreamEnvironment: 'dev',
    87                                  },
    88                              },
    89                          },
    90                      },
    91                      {
    92                          uuid: '00000000-0000-0000-0000-000000000003',
    93                          createdAt: new Date('2024-02-12T09:46:00Z'),
    94                          eventType: {
    95                              $case: 'deploymentEvent',
    96                              deploymentEvent: {
    97                                  application: 'app',
    98                                  targetEnvironment: 'staging',
    99                                  releaseTrainSource: {
   100                                      upstreamEnvironment: 'dev',
   101                                      targetEnvironmentGroup: 'staging-group',
   102                                  },
   103                              },
   104                          },
   105                      },
   106                      {
   107                          uuid: '00000000-0000-0000-0000-000000000004',
   108                          createdAt: new Date('2024-02-13T09:46:00Z'),
   109                          eventType: {
   110                              $case: 'lockPreventedDeploymentEvent',
   111                              lockPreventedDeploymentEvent: {
   112                                  application: 'app',
   113                                  environment: 'dev',
   114                                  lockMessage: 'locked',
   115                                  lockType: LockPreventedDeploymentEvent_LockType.LOCK_TYPE_ENV,
   116                              },
   117                          },
   118                      },
   119                      {
   120                          uuid: '00000000-0000-0000-0000-000000000005',
   121                          createdAt: new Date('2024-02-13T09:46:00Z'),
   122                          eventType: {
   123                              $case: 'replacedByEvent',
   124                              replacedByEvent: {
   125                                  application: 'app',
   126                                  environment: 'dev',
   127                                  replacedByCommitId: '1234567891011121314ABCD',
   128                              },
   129                          },
   130                      },
   131                  ],
   132              },
   133              expectedTitle: 'Commit: tomato',
   134              expectedCommitDescriptionTable: {
   135                  head: ['Commit Hash:', 'Commit Message:', 'Touched apps:'],
   136                  body: [['potato', `tomato Commit message body line 1 Commit message body line 2`, 'google, windows']],
   137              },
   138              expectedEventsTable: {
   139                  head: ['Date:', 'Event Description:', 'Environments:'],
   140                  body: [
   141                      ['2024-02-09T09:46:00', 'received data about this commit for the first time', 'dev, staging'],
   142                      ['2024-02-10T09:46:00', 'Manual deployment of application app to environment dev', 'dev'],
   143                      [
   144                          '2024-02-11T09:46:00',
   145                          'Release train deployment of application app from environment dev to environment staging',
   146                          'staging',
   147                      ],
   148                      [
   149                          '2024-02-12T09:46:00',
   150                          'Release train deployment of application app on environment group staging-group from environment dev to environment staging',
   151                          'staging',
   152                      ],
   153                      [
   154                          '2024-02-13T09:46:00',
   155                          'Application app was blocked from deploying due to an environment lock with message "locked"',
   156                          'dev',
   157                      ],
   158                      ['2024-02-13T09:46:00', 'This commit was replaced by 12345678 on dev.', 'dev'],
   159                  ],
   160              },
   161          },
   162      ];
   163  
   164      const verifyTable = (actualTable: HTMLTableElement, expectedTable: Table) => {
   165          // header verification
   166          const actualHeaders = actualTable.getElementsByTagName('thead');
   167          expect(actualHeaders).toHaveLength(1); // there should be 1 header line
   168  
   169          const actualHeadersRows = actualHeaders[0].getElementsByTagName('tr');
   170          expect(actualHeadersRows).toHaveLength(1); // there should be 1 row in the header line
   171  
   172          const actualHeaderFields = actualHeadersRows[0].getElementsByTagName('th');
   173          expect(actualHeaderFields).toHaveLength(expectedTable.head.length);
   174  
   175          for (let i = 0; i < actualHeaderFields.length; i++) {
   176              expect(actualHeaderFields[i].innerHTML).toEqual(expectedTable.head[i]);
   177          }
   178  
   179          // rows verification
   180          const actualBody = actualTable.getElementsByTagName('tbody');
   181          expect(actualBody).toHaveLength(1);
   182  
   183          const actualRows = actualBody[0].getElementsByTagName('tr');
   184          expect(actualRows).toHaveLength(expectedTable.body.length);
   185  
   186          for (let i = 0; i < actualRows.length; i++) {
   187              const actualRowFields = actualRows[i].getElementsByTagName('td');
   188              expect(actualRowFields).toHaveLength(expectedTable.body[i].length);
   189  
   190              for (let j = 0; j < actualHeaderFields.length; j++) {
   191                  expect(actualRowFields[j]).toHaveTextContent(expectedTable.body[i][j]);
   192              }
   193          }
   194      };
   195  
   196      for (const testCase of testCases) {
   197          const { container } = render(
   198              <MemoryRouter>
   199                  <CommitInfo commitInfo={testCase.commitInfo} />
   200              </MemoryRouter>
   201          );
   202  
   203          // first h1 is "Planned Actions", second h1 is actually our CommitInfo component:
   204          expect(container.getElementsByTagName('h1').length).toEqual(2);
   205          expect(container.getElementsByTagName('h1')[1]).toHaveTextContent(testCase.expectedTitle);
   206  
   207          const tables = container.getElementsByTagName('table');
   208  
   209          expect(tables.length).toEqual(2); // one table for commit description and one table for events
   210  
   211          const actualCommitDescriptionTable = tables[0];
   212          const actualEventsTable = tables[1];
   213  
   214          verifyTable(actualCommitDescriptionTable, testCase.expectedCommitDescriptionTable);
   215          verifyTable(actualEventsTable, testCase.expectedEventsTable);
   216      }
   217  });
   218  
   219  describe('CommitInfo component renders next and previous buttons correctly', () => {
   220      type Table = {
   221          head: string[];
   222          // NOTE: newlines, if there are any, will effectively be removed, since they will be checked using .toHaveTextContent
   223          body: string[][];
   224      };
   225  
   226      type TestCase = {
   227          commitInfo: GetCommitInfoResponse;
   228          name: string;
   229          expectedTitle: string;
   230          expectedCommitDescriptionTable: Table;
   231          expectedButtons: string[];
   232      };
   233  
   234      const testCases: TestCase[] = [
   235          {
   236              name: 'Both buttons render when there information for both commits exist',
   237              commitInfo: {
   238                  commitHash: 'potato',
   239                  commitMessage: `tomato
   240                  
   241          Commit message body line 1
   242          Commit message body line 2`,
   243                  touchedApps: ['google'],
   244                  nextCommitHash: '123456789',
   245                  previousCommitHash: '987654321',
   246                  events: [],
   247              },
   248              expectedTitle: 'Commit: tomato',
   249              expectedCommitDescriptionTable: {
   250                  head: ['Commit Hash:', 'Commit Message:', 'Touched apps:'],
   251                  body: [['potato', `tomato Commit message body line 1 Commit message body line 2`, 'google']],
   252              },
   253              expectedButtons: ['Previous Commit', 'Next Commit'],
   254          },
   255          {
   256              name: 'Previous is correctly hidden.',
   257              commitInfo: {
   258                  commitHash: 'potato',
   259                  commitMessage: `tomato
   260                  
   261          Commit message body line 1
   262          Commit message body line 2`,
   263                  touchedApps: ['google'],
   264                  nextCommitHash: '123456789',
   265                  previousCommitHash: '',
   266                  events: [],
   267              },
   268              expectedTitle: 'Commit: tomato',
   269              expectedCommitDescriptionTable: {
   270                  head: ['Commit Hash:', 'Commit Message:', 'Touched apps:'],
   271                  body: [['potato', `tomato Commit message body line 1 Commit message body line 2`, 'google']],
   272              },
   273              expectedButtons: ['Next Commit'],
   274          },
   275          {
   276              name: 'Next is correctly hidden',
   277              commitInfo: {
   278                  commitHash: 'potato',
   279                  commitMessage: `tomato
   280                  
   281          Commit message body line 1
   282          Commit message body line 2`,
   283                  touchedApps: ['google'],
   284                  nextCommitHash: '',
   285                  previousCommitHash: '987654321',
   286                  events: [],
   287              },
   288              expectedTitle: 'Commit: tomato',
   289              expectedCommitDescriptionTable: {
   290                  head: ['Commit Hash:', 'Commit Message:', 'Touched apps:'],
   291                  body: [['potato', `tomato Commit message body line 1 Commit message body line 2`, 'google']],
   292              },
   293              expectedButtons: ['Previous Commit'],
   294          },
   295          {
   296              name: 'No button shows when no info is provided',
   297              commitInfo: {
   298                  commitHash: 'potato',
   299                  commitMessage: `tomato
   300                  
   301          Commit message body line 1
   302          Commit message body line 2`,
   303                  touchedApps: ['google'],
   304                  nextCommitHash: '',
   305                  previousCommitHash: '',
   306                  events: [],
   307              },
   308              expectedTitle: 'Commit: tomato',
   309              expectedCommitDescriptionTable: {
   310                  head: ['Commit Hash:', 'Commit Message:', 'Touched apps:'],
   311                  body: [['potato', `tomato Commit message body line 1 Commit message body line 2`, 'google']],
   312              },
   313              expectedButtons: [],
   314          },
   315          {
   316              name: 'No button shows when more than one app is touched',
   317              commitInfo: {
   318                  commitHash: 'potato',
   319                  commitMessage: `tomato
   320                  
   321          Commit message body line 1
   322          Commit message body line 2`,
   323                  touchedApps: ['google', 'microsoft'],
   324                  nextCommitHash: '123456789',
   325                  previousCommitHash: '987654321',
   326                  events: [],
   327              },
   328              expectedTitle: 'Commit: tomato',
   329              expectedCommitDescriptionTable: {
   330                  head: ['Commit Hash:', 'Commit Message:', 'Touched apps:'],
   331                  body: [['potato', `tomato Commit message body line 1 Commit message body line 2`, 'google']],
   332              },
   333              expectedButtons: [],
   334          },
   335      ];
   336      describe.each(testCases)(`Test Buttons Work`, (testCase) => {
   337          it(testCase.name, () => {
   338              const { container } = render(
   339                  <MemoryRouter>
   340                      <CommitInfo commitInfo={testCase.commitInfo} />
   341                  </MemoryRouter>
   342              );
   343  
   344              const targetElements = container.getElementsByClassName('history-button-container');
   345              expect(targetElements.length).toEqual(testCase.expectedButtons.length);
   346              for (let i = 0; i < testCase.expectedButtons.length; i++) {
   347                  expect(targetElements[i]).toHaveTextContent(testCase.expectedButtons[i]);
   348              }
   349          });
   350      });
   351  });