diff --git a/cypress/e2e/po/components/sortable-table.po.ts b/cypress/e2e/po/components/sortable-table.po.ts index 5f59b1849b4..39412587d89 100644 --- a/cypress/e2e/po/components/sortable-table.po.ts +++ b/cypress/e2e/po/components/sortable-table.po.ts @@ -186,8 +186,8 @@ export default class SortableTablePo extends ComponentPo { * @param expected number of rows shown * @returns */ - checkRowCount(isEmpty: boolean, expected: number, hasFilter = false) { - return this.rowElements().should((el) => { + checkRowCount(isEmpty: boolean, expected: number, options?, hasFilter = false) { + return this.rowElements(options).should((el) => { if (isEmpty) { expect(el).to.have.length(expected); expect(el).to.have.text(hasFilter ? 'There are no rows which match your search query.' : 'There are no rows to show.'); diff --git a/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke1.spec.ts b/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke1.spec.ts index 2f6396023e3..274f0377442 100644 --- a/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke1.spec.ts +++ b/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke1.spec.ts @@ -5,18 +5,23 @@ import ClusterManagerDetailRke1AmazonEc2PagePo from '@/cypress/e2e/po/detail/pro import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po'; import LoadingPo from '@/cypress/e2e/po/components/loading.po'; import EmberBannersPo from '@/cypress/e2e/po/components/ember/ember-banners.po'; +import { LONG_TIMEOUT_OPT, MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; /****** * Running this test will delete node templates and cloud credentials resources from the target cluster ******/ // will only run this in jenkins pipeline where cloud credentials are stored -describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { +describe('Deploy RKE1 cluster using node driver on Amazon EC2', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { const clusterList = new ClusterManagerListPagePo(); const createRKE1ClusterPage = new ClusterManagerCreateRke1Amazonec2PagePo(); + const loadingPo = new LoadingPo('.loading-indicator'); + let removeNodeTemplate = false; let cloudcredentialId = ''; let nodeTemplateId = ''; + let clusterId = ''; + const k8sVersions = []; const homePage = new HomePagePo(); const homeClusterList = homePage.list(); @@ -65,22 +70,9 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', cy.createE2EResourceName('rke1ec2clusterdesc').as('rke1Ec2ClusterDescription'); cy.createE2EResourceName('template').as('templateName'); cy.createE2EResourceName('node').as('nodeName'); - cy.getRancherResource('v3', 'clusters', null, null).then((resp: Cypress.Response) => { - const data = resp.body.data; - - data.forEach((item: any) => { - cy.get('@rke1Ec2ClusterName').then((name) => { - if (item.name === name) { - cy.wrap(item['id']).as('clusterId'); - } else { - cy.log(`${ name } does not exist`); - } - }); - }); - }); }); - it('can provision a Amazon EC2 rke1 cluster with Amazon cloud provider', function() { + it('can create an RKE1 cluster using Amazon cloud provider', function() { const addNodeTemplateForm = createRKE1ClusterPage.addNodeTemplateForm(); ClusterManagerListPagePo.navTo(); @@ -88,8 +80,9 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', clusterList.createCluster(); createRKE1ClusterPage.rkeToggle().set('RKE1'); createRKE1ClusterPage.selectCreate(0); - createRKE1ClusterPage.rke2PageTitle().should('include', 'Create Amazon EC2'); createRKE1ClusterPage.waitForPage('type=amazonec2&rkeType=rke1'); + loadingPo.checkNotExists(); + createRKE1ClusterPage.rke1PageTitle().should('contain', 'Add Cluster - Amazon EC2'); createRKE1ClusterPage.addNodeTemplate(); // create amazon ec2 cloud credential and node template @@ -131,59 +124,63 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected(); // Get kubernetes version options and store them in variables - createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().getOptions().each((el, index) => { - cy.wrap(el.text().trim()).as(`k8sVersion${ index }`); + createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().getOptions().each((el) => { + k8sVersions.push(el.text().trim()); }) - .then(function() { - createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().selectMenuItemByOption(this.k8sVersion0); + .then(() => { + createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().selectMenuItemByOption(k8sVersions[0]); }); cy.intercept('POST', 'v3/cluster?_replace=true').as('createRke1Cluster'); createRKE1ClusterPage.createRKE1(); - cy.wait('@createRke1Cluster').then(function(req) { - expect(req.response?.statusCode).to.eq(201); - expect(req.response?.body).to.have.property('type', 'cluster'); - expect(req.response?.body).to.have.property('name', this.rke1Ec2ClusterName); - expect(req.response?.body.rancherKubernetesEngineConfig).to.have.property('kubernetesVersion', this.k8sVersion0); - cy.wrap(req.response?.body.id).as('clusterId'); + cy.wait('@createRke1Cluster').then(({ response }) => { + expect(response?.statusCode).to.eq(201); + expect(response?.body).to.have.property('type', 'cluster'); + expect(response?.body).to.have.property('name', this.rke1Ec2ClusterName); + expect(response?.body.rancherKubernetesEngineConfig).to.have.property('kubernetesVersion', k8sVersions[0]); + clusterId = response?.body.id; }); clusterList.waitForPage(); + clusterList.list().state(this.rke1Ec2ClusterName).should('contain.text', 'Provisioning'); + }); + + it('can see details of cluster in cluster list', function() { + ClusterManagerListPagePo.navTo(); + clusterList.waitForPage(); // check Architecture // testing https://github.com/rancher/dashboard/issues/10831 - clusterList.list().version(this.rke1Ec2ClusterName).should('contain', '—').and('not.contain', 'Unknown'); + clusterList.list().version(this.rke1Ec2ClusterName).should('contain.text', '—').and('not.contain.text', 'Unknown'); // check states - clusterList.list().state(this.rke1Ec2ClusterName).should('contain', 'Provisioning'); + clusterList.list().state(this.rke1Ec2ClusterName).contains('Waiting', { timeout: 700000 }); clusterList.list().state(this.rke1Ec2ClusterName).contains('Active', { timeout: 700000 }); // check k8s version - clusterList.sortableTable().rowWithName(this.rke1Ec2ClusterName).column(3).contains('—') - .should('not.exist', { timeout: 5000 }); - clusterList.list().version(this.rke1Ec2ClusterName).then(function(el) { - const shortVersion = this.k8sVersion0.split('-'); + clusterList.sortableTable().rowWithName(this.rke1Ec2ClusterName).column(3).contains('—', { timeout: 15000 }) + .should('not.exist'); + clusterList.list().version(this.rke1Ec2ClusterName).then((el) => { + const shortVersion = k8sVersions[0].split('-'); expect(el.text().trim()).contains(shortVersion[0]); }); // check provider - clusterList.list().provider(this.rke1Ec2ClusterName).should('contain', 'Amazon EC2'); - clusterList.list().provider(this.rke1Ec2ClusterName).should('contain', 'RKE1'); + clusterList.list().provider(this.rke1Ec2ClusterName).should('contain.text', 'Amazon EC2'); + clusterList.list().providerSubType(this.rke1Ec2ClusterName).should('contain.text', 'RKE1'); // check machines - clusterList.list().machines(this.rke1Ec2ClusterName).should('contain', 1); + clusterList.list().machines(this.rke1Ec2ClusterName).should('contain.text', '1'); // check cluster details page > machine pools - cy.get('@clusterId').then(function(clusterId) { - const clusterDetails = new ClusterManagerDetailRke1AmazonEc2PagePo(undefined, clusterId); - - clusterList.list().name(this.rke1Ec2ClusterName).click(); - clusterDetails.waitForPage(null, 'node-pools'); - clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName); - clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(this.nodeName) - .next('tr.main-row') - .should('contain', 'Active'); - }); + const clusterDetails = new ClusterManagerDetailRke1AmazonEc2PagePo(undefined, clusterId); + + clusterList.list().name(this.rke1Ec2ClusterName).click(); + clusterDetails.waitForPage(null, 'node-pools'); + clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName); + clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(this.nodeName) + .next('tr.main-row') + .should('contain.text', 'Active'); // https://github.com/rancher/dashboard/issues/10441 - covering RKE1/ember world descriptions HomePagePo.navTo(); @@ -198,14 +195,12 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', clusterList.waitForPage(); // cluster details page - const clusterDetails = new ClusterManagerDetailRke1AmazonEc2PagePo(undefined, this.clusterId); + const clusterDetails = new ClusterManagerDetailRke1AmazonEc2PagePo(undefined, clusterId); clusterList.list().actionMenu(this.rke1Ec2ClusterName).getMenuItem('Edit Config').click(); clusterDetails.waitForPage('mode=edit'); clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName); - const loadingPo = new LoadingPo('.loading-indicator'); - loadingPo.checkNotExists(); createRKE1ClusterPage.nodePoolTable().addNodePool(); createRKE1ClusterPage.nodePoolTable().name(1).set(this.nodeName); @@ -224,11 +219,10 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected(); // save changes - cy.intercept('PUT', `v3/clusters/${ this.clusterId }?_replace=true`).as('saveRke1Cluster'); + cy.intercept('POST', `/v3/nodepool`).as('updateCluster'); createRKE1ClusterPage.saveRKE1(); - cy.wait('@saveRke1Cluster').then((req) => { - expect(req.response?.statusCode).to.eq(200); - }); + cy.wait('@updateCluster').its('response.statusCode').should('eq', 201); + clusterList.waitForPage(); // check states on cluster details page > machine pools clusterList.list().name(this.rke1Ec2ClusterName).click(); @@ -236,19 +230,18 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', clusterDetails.resourceDetail().title().should('contain', this.rke1Ec2ClusterName); clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`) .next('tr.main-row') - .should('contain', 'Provisioning'); + .should('contain.text', 'Provisioning'); clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`) .next('tr.main-row', { timeout: 360000 }) - .should('contain', 'Registering'); + .should('contain.text', 'Registering'); clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`) .next('tr.main-row', { timeout: 360000 }) - .should('contain', 'Active'); + .should('contain.text', 'Active'); }); - it('can delete a Amazon EC2 RKE1 cluster', function() { + it('can delete an Amazon EC2 RKE1 cluster', function() { ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); - clusterList.list().state(this.rke1Ec2ClusterName).contains('Active', { timeout: 120000 }); clusterList.list().actionMenu(this.rke1Ec2ClusterName).getMenuItem('Delete').click(); clusterList.sortableTable().rowNames('.cluster-link').then((rows: any) => { @@ -258,13 +251,15 @@ describe('Provision Node driver RKE1 cluster with AWS', { testIsolation: 'off', promptRemove.remove(); clusterList.waitForPage(); - clusterList.list().state(this.rke1Ec2ClusterName).should('contain', 'Removing'); - clusterList.sortableTable().checkRowCount(false, rows.length - 1); + clusterList.list().state(this.rke1Ec2ClusterName).contains('Removing', LONG_TIMEOUT_OPT); + clusterList.sortableTable().checkRowCount(false, rows.length - 1, MEDIUM_TIMEOUT_OPT); clusterList.sortableTable().rowNames('.cluster-link').should('not.contain', this.rke1Ec2ClusterName); }); }); after('clean up', () => { + // delete cluster: needed here in case the delete test fails + cy.deleteRancherResource('v1', 'provisioning.cattle.io.clusters', `fleet-default/${ clusterId }`, false); if (removeNodeTemplate) { // delete node template cy.deleteNodeTemplate(nodeTemplateId).then(() => { diff --git a/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke2.spec.ts b/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke2.spec.ts index e7889c49687..49ef462e3de 100644 --- a/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke2.spec.ts +++ b/cypress/e2e/tests/pages/manager/cluster-provisioning-amazon-ec2-rke2.spec.ts @@ -4,13 +4,18 @@ import ClusterManagerListPagePo from '@/cypress/e2e/po/pages/cluster-manager/clu import ClusterManagerDetailRke2AmazonEc2PagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-rke2-amazon.po'; import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po'; import LoadingPo from '@/cypress/e2e/po/components/loading.po'; -import TabbedPo from '~/cypress/e2e/po/components/tabbed.po'; +import TabbedPo from '@/cypress/e2e/po/components/tabbed.po'; +import { MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; // will only run this in jenkins pipeline where cloud credentials are stored -describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { +describe('Deploy RKE2 cluster using node driver on Amazon EC2', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { const clusterList = new ClusterManagerListPagePo(); + const loadingPo = new LoadingPo('.loading-indicator'); + let removeCloudCred = false; let cloudcredentialId = ''; + let k8sVersion = ''; + let clusterId = ''; before(() => { cy.login(); @@ -39,11 +44,11 @@ describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@ cy.createE2EResourceName('ec2cloudcredential').as('ec2CloudCredentialName'); }); - it('can provision a Amazon EC2 RKE2 cluster with Amazon cloud provider', function() { + it('can create an RKE2 cluster using Amazon cloud provider', function() { const createRKE2ClusterPage = new ClusterManagerCreateRke2AmazonPagePo(); const cloudCredForm = createRKE2ClusterPage.cloudCredentialsForm(); - const clusterDetails = new ClusterManagerDetailRke2AmazonEc2PagePo(undefined, this.rke2Ec2ClusterName); - const tabbedPo = new TabbedPo('[data-testid="tabbed-block"]'); + + cy.intercept('GET', '/v1-rke2-release/releases').as('getRke2Releases'); // create cluster ClusterManagerListPagePo.navTo(); @@ -51,6 +56,7 @@ describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@ clusterList.createCluster(); createRKE2ClusterPage.rkeToggle().set('RKE2/K3s'); createRKE2ClusterPage.selectCreate(0); + loadingPo.checkNotExists(); createRKE2ClusterPage.rke2PageTitle().should('include', 'Create Amazon EC2'); createRKE2ClusterPage.waitForPage('type=amazonec2&rkeType=rke2'); @@ -70,55 +76,73 @@ describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@ removeCloudCred = true; }); - const loadingPo = new LoadingPo('.loading-indicator'); - cy.wait('@pageLoad').its('response.statusCode').should('eq', 200); loadingPo.checkNotExists(); createRKE2ClusterPage.waitForPage('type=amazonec2&rkeType=rke2', 'basic'); createRKE2ClusterPage.nameNsDescription().name().set(this.rke2Ec2ClusterName); createRKE2ClusterPage.nameNsDescription().description().set(`${ this.rke2Ec2ClusterName }-description`); - // Get kubernetes version options and store them in variables - createRKE2ClusterPage.basicsTab().kubernetesVersions().toggle(); - createRKE2ClusterPage.basicsTab().kubernetesVersions().getOptions().each((el, index) => { - cy.wrap(el.text().trim()).as(`k8sVersion${ index }`); - }) - .then(function() { - createRKE2ClusterPage.basicsTab().kubernetesVersions().clickOptionWithLabel(this.k8sVersion1); - }); + // Get latest kubernetes version + cy.wait('@getRke2Releases').then(({ response }) => { + expect(response.statusCode).to.eq(200); + const length = response.body.data.length - 1; - createRKE2ClusterPage.machinePoolTab().networks().toggle(); - createRKE2ClusterPage.machinePoolTab().networks().clickOptionWithLabel('maxdualstack-vpc'); + k8sVersion = response.body.data[length].id; + cy.wrap(k8sVersion).as('k8sVersion'); + }); - cy.intercept('POST', 'v1/provisioning.cattle.io.clusters').as('createRke2Cluster'); - createRKE2ClusterPage.create(); - cy.wait('@createRke2Cluster').then(({ response }) => { - expect(response?.statusCode).to.eq(201); - expect(response?.body).to.have.property('kind', 'Cluster'); - expect(response?.body.metadata).to.have.property('name', this.rke2Ec2ClusterName); - expect(response?.body.spec).to.have.property('kubernetesVersion', this.k8sVersion1); + cy.get('@k8sVersion').then((version) => { + createRKE2ClusterPage.basicsTab().kubernetesVersions().toggle(); + createRKE2ClusterPage.basicsTab().kubernetesVersions().clickOptionWithLabel(version); + + createRKE2ClusterPage.machinePoolTab().networks().toggle(); + createRKE2ClusterPage.machinePoolTab().networks().clickOptionWithLabel('maxdualstack-vpc'); + + cy.intercept('POST', 'v1/provisioning.cattle.io.clusters').as('createRke2Cluster'); + createRKE2ClusterPage.create(); + cy.wait('@createRke2Cluster').then(({ response }) => { + expect(response?.statusCode).to.eq(201); + expect(response?.body).to.have.property('kind', 'Cluster'); + expect(response?.body.metadata).to.have.property('name', this.rke2Ec2ClusterName); + expect(response?.body.spec).to.have.property('kubernetesVersion').contains(version); + clusterId = response?.body.id; + }); + clusterList.waitForPage(); + clusterList.list().state(this.rke2Ec2ClusterName).should('contain.text', 'Reconciling'); }); + }); + + it('can see details of cluster in cluster list', function() { + ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); // check Architecture // testing https://github.com/rancher/dashboard/issues/10831 - clusterList.list().version(this.rke2Ec2ClusterName).should('contain', '—').and('not.contain', 'Mixed'); + clusterList.list().version(this.rke2Ec2ClusterName).should('contain.text', '—').and('not.contain.text', 'Mixed'); // check states - clusterList.list().state(this.rke2Ec2ClusterName).should('contain', 'Reconciling'); - clusterList.list().state(this.rke2Ec2ClusterName).should('contain', 'Updating'); + clusterList.list().state(this.rke2Ec2ClusterName).should('contain.text', 'Updating'); clusterList.list().state(this.rke2Ec2ClusterName).contains('Active', { timeout: 700000 }); // check k8s version - clusterList.list().version(this.rke2Ec2ClusterName).then(function(el) { - expect(el.text().trim()).contains(this.k8sVersion1); + clusterList.list().version(this.rke2Ec2ClusterName).then((el) => { + expect(el.text().trim()).contains(k8sVersion); }); // check provider - clusterList.list().provider(this.rke2Ec2ClusterName).should('contain', 'Amazon EC2'); + clusterList.list().provider(this.rke2Ec2ClusterName).should('contain.text', 'Amazon EC2'); + clusterList.list().providerSubType(this.rke2Ec2ClusterName).should('contain.text', 'RKE2'); // check machines - clusterList.list().machines(this.rke2Ec2ClusterName).should('contain', 1); + clusterList.list().machines(this.rke2Ec2ClusterName).should('contain.text', '1'); + }); + + it('cluster details page', function() { + const clusterDetails = new ClusterManagerDetailRke2AmazonEc2PagePo(undefined, this.rke2Ec2ClusterName); + const tabbedPo = new TabbedPo('[data-testid="tabbed-block"]'); + + ClusterManagerListPagePo.navTo(); + clusterList.waitForPage(); // check cluster details page > machine pools clusterList.list().name(this.rke2Ec2ClusterName).click(); @@ -130,14 +154,21 @@ describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@ ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); clusterList.clickOnClusterName(this.rke2Ec2ClusterName); - clusterDetails.selectTab(tabbedPo, '[data-testid="btn-events"'); + clusterDetails.waitForPage(null, 'machine-pools'); + clusterDetails.selectTab(tabbedPo, '[data-testid="btn-events"]'); clusterDetails.recentEventsList().checkTableIsEmpty(); + }); + + it('can create snapshot', function() { + const clusterDetails = new ClusterManagerDetailRke2AmazonEc2PagePo(undefined, this.rke2Ec2ClusterName); + const tabbedPo = new TabbedPo('[data-testid="tabbed-block"]'); // check cluster details page > snapshots ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); clusterList.clickOnClusterName(this.rke2Ec2ClusterName); - clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"'); + clusterDetails.waitForPage(null, 'machine-pools'); + clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"]'); clusterDetails.snapshotsList().checkTableIsEmpty(); // create on demand snapshot @@ -146,16 +177,16 @@ describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@ // wait for cluster to be active ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); - clusterList.list().state(this.rke2Ec2ClusterName).should('contain', 'Updating'); + clusterList.list().state(this.rke2Ec2ClusterName).should('contain.text', 'Updating'); clusterList.list().state(this.rke2Ec2ClusterName).contains('Active', { timeout: 700000 }); // check snapshot exist clusterList.clickOnClusterName(this.rke2Ec2ClusterName); - clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"'); + clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"]'); clusterDetails.snapshotsList().checkSnapshotExist(`on-demand-${ this.rke2Ec2ClusterName }`); }); - it('can delete a Amazon EC2 RKE2 cluster', function() { + it('can delete an Amazon EC2 RKE2 cluster', function() { ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); clusterList.list().actionMenu(this.rke2Ec2ClusterName).getMenuItem('Delete').click(); @@ -168,12 +199,14 @@ describe('Provision Node driver RKE2 cluster', { testIsolation: 'off', tags: ['@ clusterList.waitForPage(); clusterList.list().state(this.rke2Ec2ClusterName).should('contain', 'Removing'); - clusterList.sortableTable().checkRowCount(false, rows.length - 1); + clusterList.sortableTable().checkRowCount(false, rows.length - 1, MEDIUM_TIMEOUT_OPT); clusterList.sortableTable().rowNames('.cluster-link').should('not.contain', this.rke2Ec2ClusterName); }); }); after('clean up', () => { + // delete cluster: needed here in case the delete test fails + cy.deleteRancherResource('v1', 'provisioning.cattle.io.clusters', clusterId, false); if (removeCloudCred) { // delete cloud cred cy.deleteRancherResource('v3', 'cloudCredentials', cloudcredentialId); diff --git a/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke1.spec.ts b/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke1.spec.ts index 604c10a6d05..6f93d6f72a6 100644 --- a/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke1.spec.ts +++ b/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke1.spec.ts @@ -5,18 +5,23 @@ import ClusterManagerDetailRke1AzurePagePo from '@/cypress/e2e/po/detail/provisi import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po'; import LoadingPo from '@/cypress/e2e/po/components/loading.po'; import EmberBannersPo from '@/cypress/e2e/po/components/ember/ember-banners.po'; +import { LONG_TIMEOUT_OPT, MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; /****** * Running this test will delete node templates and cloud credentials resources from the target cluster ******/ // will only run this in jenkins pipeline where cloud credentials are stored -describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { +describe('Deploy RKE1 cluster using node driver on Azure', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { const clusterList = new ClusterManagerListPagePo(); const createRKE1ClusterPage = new ClusterManagerCreateRke1AzurePagePo(); + const loadingPo = new LoadingPo('.loading-indicator'); + let removeNodeTemplate = false; let cloudcredentialId = ''; let nodeTemplateId = ''; + let clusterId = ''; + const k8sVersions = []; before(() => { cy.login(); @@ -61,22 +66,9 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' cy.createE2EResourceName('rke1azurecluster').as('rke1AzureClusterName'); cy.createE2EResourceName('template').as('templateName'); cy.createE2EResourceName('node').as('nodeName'); - cy.getRancherResource('v3', 'clusters', null, null).then((resp: Cypress.Response) => { - const data = resp.body.data; - - data.forEach((item: any) => { - cy.get('@rke1AzureClusterName').then((name) => { - if (item.name === name) { - cy.wrap(item['id']).as('clusterId'); - } else { - cy.log(`${ name } does not exist`); - } - }); - }); - }); }); - it('can provision a azure rke1 cluster with Azure cloud provider', function() { + it('can create an RKE1 cluster using Azure cloud provider', function() { const addNodeTemplateForm = createRKE1ClusterPage.addNodeTemplateForm(); ClusterManagerListPagePo.navTo(); @@ -84,8 +76,9 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' clusterList.createCluster(); createRKE1ClusterPage.rkeToggle().set('RKE1'); createRKE1ClusterPage.selectCreate(1); - createRKE1ClusterPage.rke2PageTitle().should('include', 'Create Azure'); createRKE1ClusterPage.waitForPage('type=azure&rkeType=rke1'); + loadingPo.checkNotExists(); + createRKE1ClusterPage.rke1PageTitle().should('contain', 'Add Cluster - Azure'); createRKE1ClusterPage.addNodeTemplate(); // create azure cloud credential and node template @@ -124,55 +117,59 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected(); // Get kubernetes version options and store them in variables - createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().getOptions().each((el, index) => { - cy.wrap(el.text().trim()).as(`k8sVersion${ index }`); + createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().getOptions().each((el) => { + k8sVersions.push(el.text().trim()); }) - .then(function() { - createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().selectMenuItemByOption(this.k8sVersion0); + .then(() => { + createRKE1ClusterPage.kubernetesOptions().kubernetesVersion().selectMenuItemByOption(k8sVersions[0]); }); cy.intercept('POST', 'v3/cluster?_replace=true').as('createRke1Cluster'); createRKE1ClusterPage.createRKE1(); - cy.wait('@createRke1Cluster').then(function(req) { - expect(req.response?.statusCode).to.eq(201); - expect(req.response?.body).to.have.property('type', 'cluster'); - expect(req.response?.body).to.have.property('name', this.rke1AzureClusterName); - expect(req.response?.body.rancherKubernetesEngineConfig).to.have.property('kubernetesVersion', this.k8sVersion0); - cy.wrap(req.response?.body.id).as('clusterId'); + cy.wait('@createRke1Cluster').then(({ response }) => { + expect(response?.statusCode).to.eq(201); + expect(response?.body).to.have.property('type', 'cluster'); + expect(response?.body).to.have.property('name', this.rke1AzureClusterName); + expect(response?.body.rancherKubernetesEngineConfig).to.have.property('kubernetesVersion', k8sVersions[0]); + clusterId = response?.body.id; }); + clusterList.waitForPage(); + clusterList.list().state(this.rke1AzureClusterName).should('contain.text', 'Provisioning'); + }); - // check states + it('can see details of cluster in cluster list', function() { + ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); - clusterList.list().state(this.rke1AzureClusterName).should('contain', 'Provisioning'); + + // check states + clusterList.list().state(this.rke1AzureClusterName).contains('Waiting', { timeout: 700000 }); clusterList.list().state(this.rke1AzureClusterName).contains('Active', { timeout: 700000 }); // check k8s version - clusterList.sortableTable().rowWithName(this.rke1AzureClusterName).column(3).contains('—') - .should('not.exist', { timeout: 5000 }); - clusterList.list().version(this.rke1AzureClusterName).then(function(el) { - const shortVersion = this.k8sVersion0.split('-'); + clusterList.sortableTable().rowWithName(this.rke1AzureClusterName).column(3).contains('—', { timeout: 15000 }) + .should('not.exist'); + clusterList.list().version(this.rke1AzureClusterName).then((el) => { + const shortVersion = k8sVersions[0].split('-'); expect(el.text().trim()).contains(shortVersion[0]); }); // check provider - clusterList.list().provider(this.rke1AzureClusterName).should('contain', 'Azure'); - clusterList.list().provider(this.rke1AzureClusterName).should('contain', 'RKE1'); + clusterList.list().provider(this.rke1AzureClusterName).should('contain.text', 'Azure'); + clusterList.list().providerSubType(this.rke1AzureClusterName).should('contain.text', 'RKE1'); // check machines - clusterList.list().machines(this.rke1AzureClusterName).should('contain', 1); + clusterList.list().machines(this.rke1AzureClusterName).should('contain.text', '1'); // check cluster details page > machine pools - cy.get('@clusterId').then(function(clusterId) { - const clusterDetails = new ClusterManagerDetailRke1AzurePagePo(undefined, clusterId); - - clusterList.list().name(this.rke1AzureClusterName).click(); - clusterDetails.waitForPage(null, 'node-pools'); - clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName); - clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(this.nodeName) - .next('tr.main-row') - .should('contain', 'Active'); - }); + const clusterDetails = new ClusterManagerDetailRke1AzurePagePo(undefined, clusterId); + + clusterList.list().name(this.rke1AzureClusterName).click(); + clusterDetails.waitForPage(null, 'node-pools'); + clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName); + clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(this.nodeName) + .next('tr.main-row') + .should('contain.text', 'Active'); }); it('can add a node to the cluster', function() { @@ -180,14 +177,12 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' clusterList.waitForPage(); // cluster details page - const clusterDetails = new ClusterManagerDetailRke1AzurePagePo(undefined, this.clusterId); + const clusterDetails = new ClusterManagerDetailRke1AzurePagePo(undefined, clusterId); clusterList.list().actionMenu(this.rke1AzureClusterName).getMenuItem('Edit Config').click(); clusterDetails.waitForPage('mode=edit'); clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName); - const loadingPo = new LoadingPo('.loading-indicator'); - loadingPo.checkNotExists(); createRKE1ClusterPage.nodePoolTable().addNodePool(); createRKE1ClusterPage.nodePoolTable().name(1).set(this.nodeName); @@ -206,11 +201,10 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' createRKE1ClusterPage.nodePoolTable().worker(1).checkOptionSelected(); // save changes - cy.intercept('PUT', `v3/clusters/${ this.clusterId }?_replace=true`).as('saveRke1Cluster'); + cy.intercept('POST', `/v3/nodepool`).as('updateCluster'); createRKE1ClusterPage.saveRKE1(); - cy.wait('@saveRke1Cluster').then((req) => { - expect(req.response?.statusCode).to.eq(200); - }); + cy.wait('@updateCluster').its('response.statusCode').should('eq', 201); + clusterList.waitForPage(); // check states on cluster details page > machine pools clusterList.list().name(this.rke1AzureClusterName).click(); @@ -218,7 +212,7 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' clusterDetails.resourceDetail().title().should('contain', this.rke1AzureClusterName); clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`) .next('tr.main-row') - .should('contain', 'Provisioning'); + .should('contain.text', 'Provisioning'); clusterDetails.machinePoolsList().resourceTable().sortableTable().groupElementWithName(`${ this.nodeName }-2`) .next('tr.main-row', { timeout: 360000 }) .should('contain', 'Registering'); @@ -227,10 +221,9 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' .should('contain', 'Active'); }); - it('can delete a Azure RKE1 cluster', function() { + it('can delete an Azure RKE1 cluster', function() { ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); - clusterList.list().state(this.rke1AzureClusterName).contains('Active', { timeout: 120000 }); clusterList.list().actionMenu(this.rke1AzureClusterName).getMenuItem('Delete').click(); clusterList.sortableTable().rowNames('.cluster-link').then((rows: any) => { @@ -240,16 +233,18 @@ describe('Provision Node driver RKE1 cluster with Azure', { testIsolation: 'off' promptRemove.remove(); clusterList.waitForPage(); - clusterList.list().state(this.rke1AzureClusterName).should('contain', 'Removing'); - clusterList.sortableTable().checkRowCount(false, rows.length - 1); + clusterList.list().state(this.rke1AzureClusterName).contains('Removing', LONG_TIMEOUT_OPT); + clusterList.sortableTable().checkRowCount(false, rows.length - 1, MEDIUM_TIMEOUT_OPT); clusterList.sortableTable().rowNames('.cluster-link').should('not.contain', this.rke1AzureClusterName); }); }); after('clean up', () => { + // delete cluster: needed here in case the delete test fails + cy.deleteRancherResource('v1', 'provisioning.cattle.io.clusters', `fleet-default/${ clusterId }`, false); if (removeNodeTemplate) { // delete node template - cy.deleteNodeTemplate(nodeTemplateId, 120000).then(() => { + cy.deleteNodeTemplate(nodeTemplateId).then(() => { // delete cloud cred cy.deleteRancherResource('v3', 'cloudCredentials', cloudcredentialId); }); diff --git a/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke2.spec.ts b/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke2.spec.ts index 8cdc5625d97..057a4f2af9e 100644 --- a/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke2.spec.ts +++ b/cypress/e2e/tests/pages/manager/cluster-provisioning-azure-rke2.spec.ts @@ -4,13 +4,16 @@ import ClusterManagerCreateRke2AzurePagePo from '@/cypress/e2e/po/edit/provision import ClusterManagerDetailRke2AzurePagePo from '@/cypress/e2e/po/detail/provisioning.cattle.io.cluster/cluster-detail-rke2-azure.po'; import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po'; import LoadingPo from '@/cypress/e2e/po/components/loading.po'; -import TabbedPo from '~/cypress/e2e/po/components/tabbed.po'; +import TabbedPo from '@/cypress/e2e/po/components/tabbed.po'; +import { MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; // will only run this in jenkins pipeline where cloud credentials are stored -describe('Provision Node driver RKE2 cluster with Azure', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { +describe('Deploy RKE2 cluster using node driver on Azure', { testIsolation: 'off', tags: ['@manager', '@adminUser', '@standardUser', '@jenkins'] }, () => { const clusterList = new ClusterManagerListPagePo(); let removeCloudCred = false; let cloudcredentialId = ''; + let k8sVersion = ''; + let clusterId = ''; before(() => { cy.login(); @@ -39,11 +42,11 @@ describe('Provision Node driver RKE2 cluster with Azure', { testIsolation: 'off' cy.createE2EResourceName('azurecloudcredential').as('azureCloudCredentialName'); }); - it('can provision a RKE2 cluster with Azure cloud provider', function() { + it('can create a RKE2 cluster using Azure cloud provider', function() { const createRKE2ClusterPage = new ClusterManagerCreateRke2AzurePagePo(); const cloudCredForm = createRKE2ClusterPage.cloudCredentialsForm(); - const clusterDetails = new ClusterManagerDetailRke2AzurePagePo(undefined, this.rke2AzureClusterName); - const tabbedPo = new TabbedPo('[data-testid="tabbed-block"]'); + + cy.intercept('GET', '/v1-rke2-release/releases').as('getRke2Releases'); // create cluster ClusterManagerListPagePo.navTo(); @@ -76,40 +79,60 @@ describe('Provision Node driver RKE2 cluster with Azure', { testIsolation: 'off' createRKE2ClusterPage.nameNsDescription().name().set(this.rke2AzureClusterName); createRKE2ClusterPage.nameNsDescription().description().set(`${ this.rke2AzureClusterName }-description`); - // Get kubernetes version options and store them in variables - createRKE2ClusterPage.basicsTab().kubernetesVersions().toggle(); - createRKE2ClusterPage.basicsTab().kubernetesVersions().getOptions().each((el, index) => { - cy.wrap(el.text().trim()).as(`k8sVersion${ index }`); - }) - .then(function() { - createRKE2ClusterPage.basicsTab().kubernetesVersions().clickOptionWithLabel(this.k8sVersion1); - }); + // Get latest kubernetes version + cy.wait('@getRke2Releases').then(({ response }) => { + expect(response.statusCode).to.eq(200); + const length = response.body.data.length - 1; - cy.intercept('POST', 'v1/provisioning.cattle.io.clusters').as('createRke2Cluster'); - createRKE2ClusterPage.create(); - cy.wait('@createRke2Cluster').then(function({ response }) { - expect(response?.statusCode).to.eq(201); - expect(response?.body).to.have.property('kind', 'Cluster'); - expect(response?.body.metadata).to.have.property('name', this.rke2AzureClusterName); - expect(response?.body.spec).to.have.property('kubernetesVersion', this.k8sVersion1); + k8sVersion = response.body.data[length].id; + cy.wrap(k8sVersion).as('k8sVersion'); }); + + cy.get('@k8sVersion').then((version) => { + createRKE2ClusterPage.basicsTab().kubernetesVersions().toggle(); + createRKE2ClusterPage.basicsTab().kubernetesVersions().clickOptionWithLabel(version); + + cy.intercept('POST', 'v1/provisioning.cattle.io.clusters').as('createRke2Cluster'); + createRKE2ClusterPage.create(); + cy.wait('@createRke2Cluster').then(function({ response }) { + expect(response?.statusCode).to.eq(201); + expect(response?.body).to.have.property('kind', 'Cluster'); + expect(response?.body.metadata).to.have.property('name', this.rke2AzureClusterName); + expect(response?.body.spec).to.have.property('kubernetesVersion', version); + clusterId = response?.body.id; + }); + clusterList.waitForPage(); + clusterList.list().state(this.rke2AzureClusterName).should('contain', 'Reconciling'); + }); + }); + + it('can see details of cluster in cluster list', function() { + ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); // check states - clusterList.list().state(this.rke2AzureClusterName).should('contain', 'Reconciling'); - clusterList.list().state(this.rke2AzureClusterName).should('contain', 'Updating'); + clusterList.list().state(this.rke2AzureClusterName).should('contain.text', 'Updating'); clusterList.list().state(this.rke2AzureClusterName).contains('Active', { timeout: 700000 }); // check k8s version - clusterList.list().version(this.rke2AzureClusterName).then(function(el) { - expect(el.text().trim()).contains(this.k8sVersion1); + clusterList.list().version(this.rke2AzureClusterName).then((el) => { + expect(el.text().trim()).contains(k8sVersion); }); // check provider - clusterList.list().provider(this.rke2AzureClusterName).should('contain', 'Azure'); + clusterList.list().provider(this.rke2AzureClusterName).should('contain.text', 'Azure'); + clusterList.list().providerSubType(this.rke2AzureClusterName).should('contain.text', 'RKE2'); // check machines - clusterList.list().machines(this.rke2AzureClusterName).should('contain', 1); + clusterList.list().machines(this.rke2AzureClusterName).should('contain.text', '1'); + }); + + it('cluster details page', function() { + const clusterDetails = new ClusterManagerDetailRke2AzurePagePo(undefined, this.rke2AzureClusterName); + const tabbedPo = new TabbedPo('[data-testid="tabbed-block"]'); + + ClusterManagerListPagePo.navTo(); + clusterList.waitForPage(); // check cluster details page > machine pools clusterList.list().name(this.rke2AzureClusterName).click(); @@ -121,14 +144,19 @@ describe('Provision Node driver RKE2 cluster with Azure', { testIsolation: 'off' ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); clusterList.clickOnClusterName(this.rke2AzureClusterName); - clusterDetails.selectTab(tabbedPo, '[data-testid="btn-events"'); + clusterDetails.selectTab(tabbedPo, '[data-testid="btn-events"]'); clusterDetails.recentEventsList().checkTableIsEmpty(); + }); + + it('can create snapshot', function() { + const clusterDetails = new ClusterManagerDetailRke2AzurePagePo(undefined, this.rke2AzureClusterName); + const tabbedPo = new TabbedPo('[data-testid="tabbed-block"]'); // check cluster details page > snapshots ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); clusterList.clickOnClusterName(this.rke2AzureClusterName); - clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"'); + clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"]'); clusterDetails.snapshotsList().checkTableIsEmpty(); // create on demand snapshot @@ -137,16 +165,16 @@ describe('Provision Node driver RKE2 cluster with Azure', { testIsolation: 'off' // wait for cluster to be active ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); - clusterList.list().state(this.rke2AzureClusterName).should('contain', 'Updating'); + clusterList.list().state(this.rke2AzureClusterName).should('contain.text', 'Updating'); clusterList.list().state(this.rke2AzureClusterName).contains('Active', { timeout: 700000 }); // check snapshot exist clusterList.clickOnClusterName(this.rke2AzureClusterName); - clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"'); + clusterDetails.selectTab(tabbedPo, '[data-testid="btn-snapshots"]'); clusterDetails.snapshotsList().checkSnapshotExist(`on-demand-${ this.rke2AzureClusterName }`); }); - it('can delete a Azure RKE2 cluster', function() { + it('can delete an Azure RKE2 cluster', function() { ClusterManagerListPagePo.navTo(); clusterList.waitForPage(); clusterList.list().actionMenu(this.rke2AzureClusterName).getMenuItem('Delete').click(); @@ -158,14 +186,16 @@ describe('Provision Node driver RKE2 cluster with Azure', { testIsolation: 'off' promptRemove.remove(); clusterList.waitForPage(); - clusterList.list().state(this.rke2AzureClusterName).should('contain', 'Removing'); + clusterList.list().state(this.rke2AzureClusterName).should('contain.text', 'Removing'); clusterList.list().state(this.rke2AzureClusterName).contains('Removing', { timeout: 200000 }).should('not.exist'); - clusterList.sortableTable().checkRowCount(false, rows.length - 1); + clusterList.sortableTable().checkRowCount(false, rows.length - 1, MEDIUM_TIMEOUT_OPT); clusterList.sortableTable().rowNames('.cluster-link').should('not.contain', this.rke2AzureClusterName); }); }); after('clean up', () => { + // delete cluster: needed here in case the delete test fails + cy.deleteRancherResource('v1', 'provisioning.cattle.io.clusters', clusterId, false); if (removeCloudCred) { // delete cloud cred cy.deleteRancherResource('v3', 'cloudCredentials', cloudcredentialId); diff --git a/cypress/globals.d.ts b/cypress/globals.d.ts index ac87ad9c3ea..85951bc2f50 100644 --- a/cypress/globals.d.ts +++ b/cypress/globals.d.ts @@ -88,7 +88,7 @@ declare global { createRancherResource(prefix: 'v3' | 'v1', resourceType: string, body: any): Chainable; waitForRancherResources(prefix: 'v3' | 'v1', resourceType: string, expectedResourcesTotal: number): Chainable; deleteRancherResource(prefix: 'v3' | 'v1' | 'k8s', resourceType: string, resourceId: string, failOnStatusCode?: boolean): Chainable; - deleteNodeTemplate(nodeTemplateId: string, timeout?: number) + deleteNodeTemplate(nodeTemplateId: string, timeout?: number, failOnStatusCode?: boolean) tableRowsPerPageAndNamespaceFilter(rows: number, cluster: string, groupBy: string, namespacefilter: string) diff --git a/cypress/support/commands/rancher-api-commands.ts b/cypress/support/commands/rancher-api-commands.ts index 758338cd39a..26ffc50f7fd 100644 --- a/cypress/support/commands/rancher-api-commands.ts +++ b/cypress/support/commands/rancher-api-commands.ts @@ -519,16 +519,32 @@ Cypress.Commands.add('waitForRancherResources', (prefix, resourceType, expectedR /** * delete a node template */ -Cypress.Commands.add('deleteNodeTemplate', (nodeTemplateId, timeout = 30000) => { - return cy.deleteRancherResource('v3', 'nodetemplate', nodeTemplateId, false).then((resp: Cypress.Response) => { - if (resp.status === 405 && (resp.body.message === 'Template is in use by a node pool.' || 'Template is in use by a node.')) { - cy.log(`error message: ${ resp.body.message }. Lets retry node deletion after ${ timeout } milliseconds`); - cy.wait(timeout); // eslint-disable-line cypress/no-unnecessary-waiting - cy.deleteRancherResource('v3', 'nodetemplate', nodeTemplateId, true); - } else { - expect(resp.status).to.be.oneOf([200, 204]); - } - }); +Cypress.Commands.add('deleteNodeTemplate', (nodeTemplateId, timeout = 30000, failOnStatusCode = false) => { + let retries = 10; + + const retry = () => { + cy.request({ + method: 'DELETE', + url: `${ Cypress.env('api') }/v3/nodetemplate/${ nodeTemplateId }`, + failOnStatusCode, + headers: { + 'x-api-csrf': token.value, + Accept: 'application/json' + }, + }).then((resp) => { + if (resp.status === 200 || resp.status === 204) return resp; + else { + cy.log(`error message: ${ resp.body.message }. Lets retry node deletion after ${ timeout } milliseconds`); + cy.wait(timeout); // eslint-disable-next-line cypress/no-unnecessary-waiting + + retries = retries - 1; + if (retries === 0) return resp; + retry(); + } + }); + }; + + return retry(); }); /**