github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/frontend-service/src/ui/components/chip/EnvironmentGroupChip.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 { EnvironmentChip, EnvironmentChipProps, EnvironmentGroupChip } from './EnvironmentGroupChip'; 17 import { fireEvent, render } from '@testing-library/react'; 18 import { Environment, EnvironmentGroup, Lock, Priority } from '../../../api/api'; 19 import { EnvironmentGroupExtended, UpdateOverview } from '../../utils/store'; 20 import { Spy } from 'spy4js'; 21 22 const mock_addAction = Spy.mockModule('../../utils/store', 'addAction'); 23 24 const makeLock = (id: string): Lock => ({ 25 message: id, 26 lockId: id, 27 }); 28 29 describe('EnvironmentChip', () => { 30 const env: Environment = { 31 name: 'Test Me', 32 distanceToUpstream: 0, 33 priority: Priority.PROD, 34 locks: {}, 35 applications: {}, 36 }; 37 const envGroup: EnvironmentGroup = { 38 distanceToUpstream: 0, 39 environments: [env], 40 environmentGroupName: 'Test Me Group', 41 priority: Priority.PROD, 42 }; 43 const getNode = (overloads?: Partial<EnvironmentChipProps>) => ( 44 <EnvironmentChip app="app2" className={'chip--test'} env={env} envGroup={envGroup} {...overloads} /> 45 ); 46 const getWrapper = (overloads?: Partial<EnvironmentChipProps>) => render(getNode(overloads)); 47 it('renders a chip', () => { 48 // given 49 UpdateOverview.set({ 50 environmentGroups: [ 51 { 52 environments: [env], 53 environmentGroupName: 'dontcare', 54 distanceToUpstream: 0, 55 priority: Priority.UNRECOGNIZED, 56 }, 57 ], 58 }); 59 // then 60 const { container } = getWrapper(); 61 expect(container.firstChild).toMatchInlineSnapshot(` 62 <div 63 class="mdc-evolution-chip chip--test environment-priority-prod" 64 role="row" 65 > 66 <span 67 class="mdc-evolution-chip__cell mdc-evolution-chip__cell--primary mdc-evolution-chip__action--primary" 68 role="gridcell" 69 > 70 <span 71 class="mdc-evolution-chip__text-name" 72 > 73 <span> 74 Test Me 75 </span> 76 </span> 77 78 <span 79 class="mdc-evolution-chip__text-numbers" 80 /> 81 <div 82 class="chip--test env-locks" 83 /> 84 </span> 85 </div> 86 `); 87 }); 88 it('renders a short form tag chip', () => { 89 const wrapper = getWrapper({ 90 smallEnvChip: true, 91 env: { 92 ...env, 93 locks: { 94 lock1: makeLock('lock1'), 95 lock2: makeLock('lock2'), 96 }, 97 }, 98 }); 99 const { container } = wrapper; 100 expect(container.querySelector('.mdc-evolution-chip__text-name')?.textContent).toBe(env.name[0].toUpperCase()); 101 // only show one lock icon in the small env tag 102 expect(container.querySelectorAll('.env-card-env-lock-icon').length).toBe(1); 103 }); 104 it('renders env locks in big env chip', () => { 105 UpdateOverview.set({ 106 environmentGroups: [ 107 { 108 environments: [ 109 { 110 ...env, 111 locks: { 112 'test-lock1': makeLock('test-lock1'), 113 'test-lock2': makeLock('test-lock2'), 114 }, 115 }, 116 ], 117 priority: Priority.UNRECOGNIZED, 118 environmentGroupName: 'dontcare', 119 distanceToUpstream: 0, 120 }, 121 ], 122 }); 123 124 const wrapper = getWrapper({ 125 // big chip shows all locks 126 smallEnvChip: false, 127 env: { 128 ...env, 129 locks: { 130 'test-lock1': makeLock('test-lock1'), 131 'test-lock2': makeLock('test-lock2'), 132 }, 133 }, 134 }); 135 136 const { container } = wrapper; 137 expect(container.querySelectorAll('.env-card-env-lock-icon').length).toBe(2); 138 const lock1 = container.querySelectorAll('.button-lock')[0]; 139 fireEvent.click(lock1); 140 mock_addAction.addAction.wasCalled(); 141 expect(mock_addAction.addAction.getCallArguments()[0]).toHaveProperty( 142 'action.deleteEnvironmentLock.lockId', 143 'test-lock1' 144 ); 145 }); 146 }); 147 148 const envGroupPairFromPrios = ( 149 envPrio: Priority, 150 envGroupPrio: Priority 151 ): { env: Environment; envGroup: EnvironmentGroup } => { 152 const env: Environment = { 153 applications: {}, 154 distanceToUpstream: -1, // shouldn't matter, if this value is used an error will be thrown 155 locks: {}, 156 name: 'Test me', 157 priority: envPrio, 158 }; 159 const envGroup: EnvironmentGroup = { 160 distanceToUpstream: -1, // shouldn't matter, if this value is used an error will be thrown 161 environmentGroupName: 'Test me group', 162 environments: [env], 163 priority: envGroupPrio, 164 }; 165 166 return { env, envGroup }; 167 }; 168 169 type TestDataEnvs = { 170 envGroupPair: { 171 env: Environment; 172 envGroup: EnvironmentGroup; 173 }; 174 expectedClass: string; 175 }; 176 177 const envChipData: Array<TestDataEnvs> = [ 178 { 179 envGroupPair: envGroupPairFromPrios(Priority.PROD, Priority.PROD), 180 expectedClass: 'prod', 181 }, 182 { 183 envGroupPair: envGroupPairFromPrios(Priority.PRE_PROD, Priority.PRE_PROD), 184 expectedClass: 'pre_prod', 185 }, 186 { 187 envGroupPair: envGroupPairFromPrios(Priority.UPSTREAM, Priority.UPSTREAM), 188 expectedClass: 'upstream', 189 }, 190 { 191 envGroupPair: envGroupPairFromPrios(Priority.OTHER, Priority.OTHER), 192 expectedClass: 'other', 193 }, 194 { 195 // important case: env and group have different priorities, the priority of the group should take precedence 196 envGroupPair: envGroupPairFromPrios(Priority.UPSTREAM, Priority.PROD), 197 expectedClass: 'prod', 198 }, 199 { 200 // important case: env and group have different priorities, the priority of the group should take precedence 201 envGroupPair: envGroupPairFromPrios(Priority.PRE_PROD, Priority.CANARY), 202 expectedClass: 'canary', 203 }, 204 ]; 205 206 describe.each(envChipData)(`EnvironmentChip with envPrio Classname`, (testcase) => { 207 it(`with envPrio=${testcase.envGroupPair.env.priority} and groupPrio=${testcase.envGroupPair.envGroup.priority}`, () => { 208 const env = testcase.envGroupPair.env; 209 const group = testcase.envGroupPair.envGroup; 210 const getNode = () => <EnvironmentChip app="app1" className={'chip--hello'} env={env} envGroup={group} />; 211 const getWrapper = () => render(getNode()); 212 const { container } = getWrapper(); 213 expect(container.firstChild).toHaveClass( 214 'mdc-evolution-chip chip--hello environment-priority-' + testcase.expectedClass 215 ); 216 }); 217 }); 218 219 const envGroupFromPrio = (prio: Priority, numEnvsInGroup: number, envs: Environment[]): EnvironmentGroupExtended => ({ 220 numberOfEnvsInGroup: numEnvsInGroup, 221 environmentGroupName: 'i am the group', 222 environments: envs, 223 distanceToUpstream: 0, 224 priority: Priority.UNRECOGNIZED, 225 }); 226 227 type TestDataGroups = { 228 envGroup: EnvironmentGroupExtended; 229 expectedClass: string; 230 expectedNumbers: string; 231 expectedDisplayName: string; 232 }; 233 234 const envFromPrio = (prio: Priority): Environment => ({ 235 name: 'Test Me', 236 distanceToUpstream: 0, 237 priority: prio, 238 locks: {}, 239 applications: {}, 240 }); 241 242 const envGroupChipData: Array<TestDataGroups> = [ 243 { 244 envGroup: envGroupFromPrio(Priority.PROD, 1, [envFromPrio(Priority.PROD)]), 245 expectedClass: 'prod', 246 expectedNumbers: '(1)', 247 expectedDisplayName: 'Test Me', 248 }, 249 { 250 envGroup: envGroupFromPrio(Priority.PROD, 3, [envFromPrio(Priority.UPSTREAM), envFromPrio(Priority.PROD)]), 251 expectedClass: 'upstream', 252 expectedNumbers: '(2/3)', 253 expectedDisplayName: 'i am the group', 254 }, 255 ]; 256 257 describe.each(envGroupChipData)(`EnvironmentGroupChip with different envs`, (testcase) => { 258 it(`with envPrio=${testcase.expectedClass}`, () => { 259 const getNode = () => ( 260 <EnvironmentGroupChip app="app1" className={'chip--hello'} envGroup={testcase.envGroup} /> 261 ); 262 const getWrapper = () => render(getNode()); 263 const { container } = getWrapper(); 264 expect(container.querySelector('.mdc-evolution-chip__text-name')?.textContent).toContain( 265 testcase.expectedDisplayName 266 ); 267 expect(container.querySelector('.mdc-evolution-chip__text-numbers')?.textContent).toContain( 268 testcase.expectedNumbers 269 ); 270 }); 271 });