github.com/rancher/elemental/tests@v0.0.0-20240517125144-ae048c615b3f/cypress/latest/support/commands.ts (about) 1 /* 2 Copyright © 2022 - 2024 SUSE LLC 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 http://www.apache.org/licenses/LICENSE-2.0 8 Unless required by applicable law or agreed to in writing, software 9 distributed under the License is distributed on an "AS IS" BASIS, 10 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 See the License for the specific language governing permissions and 12 limitations under the License. 13 */ 14 import 'cypress-file-upload'; 15 import * as utils from "~/support/utils"; 16 17 // Global 18 interface hardwareLabels { 19 [key: string]: string; 20 }; 21 22 const hwLabels: hardwareLabels = { 23 'CPUModel': '${System Data/CPU/Model}', 24 'CPUVendor': '${System Data/CPU/Vendor}', 25 'NumberBlockDevices': '${System Data/Block Devices/Number Devices}', 26 'NumberNetInterface': '${System Data/Network/Number Interfaces}', 27 'CPUVendorTotalCPUCores': '${System Data/CPU/Total Cores}', 28 'TotalCPUThread': '${System Data/CPU/Total Threads}', 29 'TotalMemory': '${System Data/Memory/Total Physical Bytes}' 30 }; 31 32 // Machine registration commands 33 // ///////////////////////////// 34 35 // Create a machine registration 36 Cypress.Commands.add('createMachReg', ( 37 machRegName, 38 namespace='fleet-default', 39 checkLabels=false, 40 checkAnnotations=false, 41 checkInventoryLabels=false, 42 checkInventoryAnnotations=false, 43 checkIsoBuilding=false, 44 customCloudConfig='', 45 checkDefaultCloudConfig=true ) => { 46 cy.clickNavMenu(["Dashboard"]); 47 cy.getBySel('button-create-registration-endpoint') 48 .click(); 49 cy.getBySel('name-ns-description-name') 50 .type(machRegName); 51 52 if (customCloudConfig != '') { 53 cy.get('input[type="file"]') 54 .attachFile({filePath: customCloudConfig}); 55 } 56 57 checkLabels ? cy.addMachRegLabel('myLabel1', 'myLabelValue1') : null; 58 checkAnnotations? cy.addMachRegAnnotation('myAnnotation1', 'myAnnotationValue1') : null; 59 checkInventoryLabels ? cy.addMachInvLabel('myInvLabel1', 'myInvLabelValue1') : null; 60 checkInventoryAnnotations ? cy.addMachInvAnnotation('myInvAnnotation1', 'myInvAnnotationValue1') : null; 61 62 cy.getBySel('form-save') 63 .contains('Create') 64 .click(); 65 66 // Make sure the machine registration is created and active 67 cy.contains('.masthead', 'Registration Endpoint: '+ machRegName + 'Active') 68 .should('exist'); 69 70 // Check the namespace 71 cy.contains('.masthead', 'Namespace: '+ namespace) 72 .should('exist'); 73 74 // Make sure there is an URL registration in the Registration URL block 75 cy.getBySel('registration-url') 76 .contains(/https:\/\/.*elemental\/registration/); 77 78 // Test ISO building feature 79 if (checkIsoBuilding) { 80 // Build the ISO according to the elemental operator version 81 // Most of the time, it uses the latest dev version but sometimes 82 // before releasing, we want to test staging/stable artifacts 83 84 if (utils.isCypressTag('upgrade') || utils.isUIVersion('stable')) { 85 cy.getBySel('select-os-version-build-media') 86 .click(); 87 } else { 88 cy.getBySel('select-media-type-build-media') 89 .click(); 90 if (utils.isBootType('raw')) { 91 cy.contains('Raw') 92 .click(); 93 } else { 94 cy.contains('Iso') 95 .click(); 96 } 97 cy.getBySel('select-os-version-build-media') 98 .click(); 99 } 100 // Never build from dev ISO in upgrade scenario 101 if (utils.isCypressTag('upgrade')) { 102 // Stable operator version is hardcoded for now 103 // Will try to improve it in next version 104 if (utils.isOperatorVersion('staging')) { 105 // In rare case, we might want to test upgrading from staging to dev 106 utils.isUpgradeOsChannel('dev') ? cy.contains('(unstable)').click(): null; 107 } else if (utils.isOperatorVersion('marketplace')) { 108 cy.contains(Cypress.env('os_version_install')) 109 .click(); 110 } else { 111 cy.contains('ISO x86_64 v2.0.2') 112 .click(); 113 } 114 } else if (utils.isOperatorVersion('registry.suse.com') || utils.isOperatorVersion('marketplace')) { 115 cy.contains('ISO x86_64 v2.0.2') 116 .click(); 117 } else { 118 cy.contains('(unstable)') 119 .click(); 120 } 121 cy.getBySel(`build-media-btn`) 122 .click(); 123 cy.getBySel(`build-media-btn`) 124 .get('.icon-spin'); 125 // Download button is disabled while ISO is building 126 cy.getBySel(`download-media-btn`).should(($input) => { 127 expect($input).to.have.attr('disabled') 128 }) 129 // Download button is enabled once ISO building done 130 cy.getBySel(`download-media-btn`, { timeout: 600000 }).should(($input) => { 131 expect($input).to.not.have.attr('disabled') 132 }) 133 cy.getBySel(`download-media-btn`) 134 .click() 135 // RAW image not available in upgrade scenario because we start from stable 136 // and RAW feature is not already available in stable 137 // upgrade condition will be removed in next elemental stable version 138 if (utils.isBootType('raw') && !utils.isCypressTag('upgrade')) { 139 cy.verifyDownload('.raw', { contains:true, timeout: 300000, interval: 5000 }); 140 } else { 141 cy.verifyDownload('.iso', { contains:true, timeout: 300000, interval: 5000 }); 142 } 143 } 144 145 // Try to download the registration file and check it 146 cy.getBySel('download-btn') 147 .click(); 148 cy.verifyDownload(machRegName + '_registrationURL.yaml'); 149 cy.contains('Saving') 150 .should('not.exist'); 151 152 // Check Cloud configuration 153 // TODO: Maybe the check may be improved in one line 154 if (checkDefaultCloudConfig) { 155 if (utils.isUIVersion('dev')) { 156 cy.getBySel('yaml-editor-code-mirror') 157 .should('include.text','config:') 158 .should('include.text','cloud-config:') 159 .should('include.text','users:') 160 .should('include.text','- name: root') 161 .should('include.text','passwd: root') 162 .should('include.text','elemental:') 163 .should('include.text','install:') 164 .should('include.text','device-selector:') 165 .should('include.text','- key: Name') 166 .should('include.text','operator: In') 167 .should('include.text','values:') 168 .should('include.text','- /dev/sda') 169 .should('include.text','- /dev/vda') 170 .should('include.text','- /dev/nvme0') 171 .should('include.text','- key: Size') 172 .should('include.text','operator: Gt') 173 .should('include.text','values:') 174 .should('include.text','- 25Gi') 175 .should('include.text','reboot: true') 176 .should('include.text','snapshotter:') 177 .should('include.text','type: btrfs') 178 .should('include.text','reset:') 179 .should('include.text','reboot: true') 180 .should('include.text','reset-oem: true') 181 .should('include.text','reset-persistent: true'); 182 } else { 183 cy.getBySel('yaml-editor-code-mirror') 184 .should('include.text','config:') 185 .should('include.text','cloud-config:') 186 .should('include.text','users:') 187 .should('include.text','- name: root') 188 .should('include.text','passwd: root') 189 .should('include.text','elemental:') 190 .should('include.text','install:') 191 .should('include.text','device: /dev/nvme0n1') 192 .should('include.text','poweroff: true'); 193 } 194 } 195 196 // Check label and annotation in YAML 197 // For now, we can only check in YAML because the fields are disabled and we cannot check their content 198 // It looks like we can use shadow DOM to catch it but too complicated for now 199 cy.contains('Registration Endpoint') 200 .click(); 201 checkLabels ? cy.checkMachRegLabel(machRegName, 'myLabel1', 'myLabelValue1') : null; 202 checkAnnotations ? cy.checkMachRegAnnotation(machRegName, 'myAnnotation1', 'myAnnotationValue1') : null; 203 }); 204 205 // Add Label to machine registration 206 Cypress.Commands.add('addMachRegLabel', (labelName, labelValue) => { 207 cy.getBySel('labels-and-annotations-block') 208 .contains('Registration Endpoint') 209 .click(); 210 cy.get('[data-testid="add-label-mach-reg"] > .footer > .btn') 211 .click(); 212 cy.get('[data-testid="add-label-mach-reg"] > .kv-container > .kv-item.key') 213 .type(labelName); 214 cy.get('[data-testid="add-label-mach-reg"] > .kv-container > .kv-item.value') 215 .type(labelValue); 216 }); 217 218 // Add Annotation to machine registration 219 Cypress.Commands.add('addMachRegAnnotation', (annotationName, annotationValue) => { 220 cy.getBySel('labels-and-annotations-block') 221 .contains('Registration Endpoint') 222 .click(); 223 cy.get('[data-testid="add-annotation-mach-reg"] > .footer > .btn') 224 .click(); 225 cy.get('[data-testid="add-annotation-mach-reg"] > .kv-container > .kv-item.key') 226 .type(annotationName); 227 cy.get('[data-testid="add-annotation-mach-reg"] > .kv-container > .kv-item.value') 228 .type(annotationValue); 229 }); 230 231 // Add Label to machine inventory 232 Cypress.Commands.add('addMachInvLabel', (labelName, labelValue, useHardwareLabels=true) => { 233 cy.getBySel('labels-and-annotations-block') 234 .contains('Inventory of Machines') 235 .click(); 236 cy.get('[data-testid="add-label-mach-inv"] > .footer > .btn') 237 .click(); 238 cy.get('[data-testid="add-label-mach-inv"] > .kv-container > .kv-item.key').type(labelName); 239 cy.get('[data-testid="add-label-mach-inv"] > .kv-container > .kv-item.value').type(labelValue); 240 if (useHardwareLabels) { 241 let nthChildIndex = 7; 242 for (const key in hwLabels) { 243 cy.get('[data-testid="add-label-mach-inv"] > .footer > .btn') 244 .click(); 245 cy.get(`[data-testid="add-label-mach-inv"] > .kv-container > :nth-child(${nthChildIndex}) > input`).type(key); 246 cy.get(`[data-testid="add-label-mach-inv"] > .kv-container > :nth-child(${nthChildIndex + 1}) 247 > .value-container > [data-testid="text-area-auto-grow"]`).type(hwLabels[key], {parseSpecialCharSequences: false}); 248 nthChildIndex += 3; 249 }; 250 }; 251 }); 252 253 // Add Annotation to machine inventory 254 Cypress.Commands.add('addMachInvAnnotation', (annotationName, annotationValue) => { 255 cy.getBySel('labels-and-annotations-block') 256 .contains('Inventory of Machines') 257 .click(); 258 cy.clickButton('Add Annotation'); 259 cy.get('[data-testid="add-annotation-mach-inv"] > .kv-container > .kv-item.key') 260 .type(annotationName); 261 cy.get('[data-testid="add-annotation-mach-inv"] > .kv-container > .kv-item.value') 262 .type(annotationValue); 263 }); 264 265 // Check machine inventory label in YAML 266 Cypress.Commands.add('checkMachInvLabel', (machRegName, labelName, labelValue, afterBoot=false, userHardwareLabels=true) => { 267 if (afterBoot == false ) { 268 cy.contains(machRegName) 269 .click(); 270 cy.get('div.actions > .role-multi-action') 271 .click() 272 cy.contains('li', 'Edit YAML') 273 .click(); 274 cy.contains('Registration Endpoint: '+ machRegName) 275 .should('exist'); 276 cy.getBySel('yaml-editor-code-mirror') 277 .contains(labelName + ': ' + labelValue); 278 if (userHardwareLabels) { 279 for (const key in hwLabels) { 280 cy.getBySel('yaml-editor-code-mirror') 281 .contains(key +': ' + hwLabels[key]); 282 }; 283 }; 284 cy.clickButton('Cancel'); 285 } else { 286 cy.getBySel('yaml-editor-code-mirror') 287 .contains(labelName + ': ' + labelValue); 288 if (userHardwareLabels) { 289 for (const key in hwLabels) { 290 cy.getBySel('yaml-editor-code-mirror') 291 .contains(key +': '); 292 }; 293 }; 294 } 295 }); 296 297 // Check machine registration label in YAML 298 Cypress.Commands.add('checkMachRegLabel', (machRegName, labelName, labelValue) => { 299 cy.contains(machRegName) 300 .click(); 301 cy.get('div.actions > .role-multi-action') 302 .click() 303 cy.contains('li', 'Edit YAML') 304 .click(); 305 cy.contains('Registration Endpoint: '+ machRegName) 306 .should('exist'); 307 cy.getBySel('yaml-editor-code-mirror') 308 .contains(labelName + ': ' + labelValue); 309 cy.clickButton('Cancel'); 310 }); 311 312 // Check machine registration annotation in YAML 313 Cypress.Commands.add('checkMachRegAnnotation', ( machRegName, annotationName, annotationValue) => { 314 cy.contains(machRegName) 315 .click(); 316 cy.get('div.actions > .role-multi-action') 317 .click() 318 cy.contains('li', 'Edit YAML') 319 .click(); 320 cy.contains('Registration Endpoint: '+ machRegName) 321 .should('exist'); 322 cy.getBySel('yaml-editor-code-mirror') 323 .contains(annotationName + ': ' + annotationValue); 324 cy.clickButton('Cancel'); 325 }); 326 327 // Edit a machine registration 328 Cypress.Commands.add('editMachReg', ( machRegName, addLabel=false, addAnnotation=false, withYAML=false) => { 329 cy.contains(machRegName) 330 .click(); 331 // Select the 3dots button and edit configuration 332 cy.get('div.actions > .role-multi-action') 333 .click() 334 if (withYAML) { 335 cy.contains('li', 'Edit YAML') 336 .click(); 337 cy.contains('metadata').as('meta') 338 cy.get('@meta').click(0,0) 339 cy.get('@meta').type('{end}{enter} labels:{enter} myLabel1: myLabelValue1'); 340 cy.contains('metadata').as('meta') 341 cy.get('@meta').click(0,0) 342 cy.get('@meta').type('{end}{enter} annotations:{enter} myAnnotation1: myAnnotationValue1'); 343 } else { 344 cy.contains('li', 'Edit Config') 345 .click(); 346 addLabel ? cy.addMachRegLabel('myLabel1', 'myLabelValue1' ) : null; 347 addAnnotation ? cy.addMachRegAnnotation('myAnnotation1', 'myAnnotationValue1') : null; 348 } 349 }); 350 351 // Delete a machine registration 352 Cypress.Commands.add('deleteMachReg', (machRegName) => { 353 cy.contains('Registration Endpoint') 354 .click(); 355 /* This code cannot be used anymore for now because of 356 https://github.com/rancher/elemental/issues/714 357 As it is not a blocker, we need to bypass it. 358 Instead of selecting resource to delete by name 359 we select all resources. 360 cy.contains(machRegName) 361 .parent() 362 .parent() 363 .click(); 364 */ 365 cy.get('[width="30"] > .checkbox-outer-container') 366 .click(); 367 cy.getBySel('sortable-table-promptRemove') 368 .contains('Delete') 369 .click(); 370 cy.confirmDelete(); 371 // Timeout should fix this issue https://github.com/rancher/elemental/issues/643 372 cy.contains(machRegName, {timeout: 20000}) 373 .should('not.exist') 374 }); 375 376 // Machine Inventory commands 377 // ///////////////////////// 378 379 // Import machine inventory 380 Cypress.Commands.add('importMachineInventory', (machineInventoryFile, machineInventoryName) => { 381 cy.clickNavMenu(["Inventory of Machines"]); 382 cy.getBySel('masthead-create-yaml') 383 .click(); 384 cy.clickButton('Read from File'); 385 cy.get('input[type="file"]') 386 .attachFile({filePath: machineInventoryFile}); 387 cy.getBySel('action-button-async-button') 388 .contains('Create') 389 .click(); 390 cy.contains('Creating') 391 .should('not.exist'); 392 cy.contains(machineInventoryName) 393 .should('exist'); 394 }); 395 396 Cypress.Commands.add('checkFilter', (filterName, testFilterOne, testFilterTwo, shouldNotMatch) => { 397 cy.clickNavMenu(["Inventory of Machines"]); 398 cy.clickButton("Add Filter"); 399 cy.get('.advanced-search-box').type(filterName); 400 cy.get('.bottom-block > .role-primary').click(); 401 (testFilterOne) ? cy.contains('test-filter-one').should('exist') : cy.contains('test-filter-one').should('not.exist'); 402 (testFilterTwo) ? cy.contains('test-filter-two').should('exist') : cy.contains('test-filter-two').should('not.exist'); 403 (shouldNotMatch) ? cy.contains('shouldnotmatch').should('exist') : cy.contains('shouldnotmatch').should('not.exist'); 404 }); 405 406 Cypress.Commands.add('checkLabelSize', (sizeToCheck) => { 407 cy.clickNavMenu(["Dashboard"]); 408 cy.getBySel('button-create-registration-endpoint') 409 .click(); 410 sizeToCheck == "name" ? cy.addMachInvLabel('labeltoolonggggggggggggggggggggggggggggggggggggggggggggggggggggg', 'mylabelvalue', false) : null; 411 sizeToCheck == "value" ? cy.addMachInvLabel('mylabelname', 'valuetoolonggggggggggggggggggggggggggggggggggggggggggggggggggggg', false) : null; 412 // A banner should appear alerting you about the size exceeded 413 cy.get('[data-testid="banner-content"]') 414 // Create button should be disabled 415 cy.getBySel('form-save').should(($input) => { 416 expect($input).to.have.attr('disabled') 417 }) 418 }); 419 420 // OS Versions commands 421 // //////////////////// 422 423 // Add an OS version channel 424 Cypress.Commands.add('addOsVersionChannel', (channelVersion) => { 425 let channelRepo = `registry.opensuse.org/isv/rancher/elemental/${channelVersion}/containers/rancher/elemental-channel:latest`; 426 if (channelVersion == "stable") { 427 channelRepo = 'registry.suse.com/rancher/elemental-channel:latest'; 428 } 429 cy.clickNavMenu(["Advanced", "OS Version Channels"]); 430 cy.getBySel('masthead-create') 431 .contains('Create') 432 .click(); 433 cy.getBySel('name-ns-description-name') 434 .type(channelVersion + "-channel"); 435 cy.getBySel('os-version-channel-path') 436 .type(channelRepo); 437 cy.getBySel('form-save') 438 .contains('Create') 439 .click(); 440 // Status changes a lot right after the creation so let's wait 10 secondes 441 // before checking 442 // eslint-disable-next-line cypress/no-unnecessary-waiting 443 cy.wait(10000); 444 // Make sure the new channel is in Active state 445 cy.contains("Active "+channelVersion+"-channel", {timeout: 50000}); 446 });