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