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