From 52a56e7460401bda294dd36a8f549dbd8ec69993 Mon Sep 17 00:00:00 2001 From: Yonas Berhe Date: Wed, 8 Jan 2025 11:00:48 -0800 Subject: [PATCH] automation: fleet cluster groups tests --- .../e2e/po/components/create-edit-view.po.ts | 4 + .../fleet/fleet.cattle.io.clustergroup.po.ts | 30 ++-- .../fleet/fleet.cattle.io.clustergroup.po.ts | 16 +- .../tests/pages/fleet/cluster-groups.spec.ts | 166 +++++++++++++----- .../e2e/tests/pages/fleet/dashboard.spec.ts | 5 +- 5 files changed, 161 insertions(+), 60 deletions(-) diff --git a/cypress/e2e/po/components/create-edit-view.po.ts b/cypress/e2e/po/components/create-edit-view.po.ts index b94c8091ac8..000e8806942 100644 --- a/cypress/e2e/po/components/create-edit-view.po.ts +++ b/cypress/e2e/po/components/create-edit-view.po.ts @@ -21,4 +21,8 @@ export default class CreateEditViewPo extends ComponentPo { saveButtonPo() :AsyncButtonPo { return new AsyncButtonPo(this.self().find('.cru-resource-footer .role-primary')); } + + editAsYaml() { + return new AsyncButtonPo(this.self().find('[data-testid="form-yaml"]')).click(); + } } diff --git a/cypress/e2e/po/edit/fleet/fleet.cattle.io.clustergroup.po.ts b/cypress/e2e/po/edit/fleet/fleet.cattle.io.clustergroup.po.ts index e792fdcb7f2..6b5aa989f88 100644 --- a/cypress/e2e/po/edit/fleet/fleet.cattle.io.clustergroup.po.ts +++ b/cypress/e2e/po/edit/fleet/fleet.cattle.io.clustergroup.po.ts @@ -1,27 +1,35 @@ import PagePo from '@/cypress/e2e/po/pages/page.po'; import AsyncButtonPo from '@/cypress/e2e/po/components/async-button.po'; -import CodeMirrorPo from '@/cypress/e2e/po/components/code-mirror.po'; - +import ResourceDetailPo from '@/cypress/e2e/po/edit/resource-detail.po'; +import NameNsDescription from '@/cypress/e2e/po/components/name-ns-description.po'; export default class FleetClusterGroupsCreateEditPo extends PagePo { - private static createPath(clusterId: string, id?: string ) { - const root = `/c/${ clusterId }/explorer/storage.k8s.io.storageclass/create`; + private static createPath(clusterId: string, workspace?: string, id?: string ) { + const root = `/c/${ clusterId }/fleet/fleet.cattle.io.clustergroup`; - return id ? `${ root }/${ id }` : `${ root }/create`; + return id ? `${ root }/${ workspace }/${ id }` : `${ root }/create`; } static goTo(path: string): Cypress.Chainable { throw new Error('invalid'); } - constructor(clusterId = '_', id?: string) { - super(FleetClusterGroupsCreateEditPo.createPath(clusterId, id)); + constructor(clusterId = '_', workspace?: string, id?: string) { + super(FleetClusterGroupsCreateEditPo.createPath(clusterId, workspace, id)); + } + + title() { + return this.self().get('.title .primaryheader h1'); + } + + nameNsDescription() { + return new NameNsDescription(this.self()); } - editAsYaml() { - return new AsyncButtonPo('[data-testid="form-yaml"]', this.self()); + saveCreateForm(): ResourceDetailPo { + return new ResourceDetailPo(this.self()); } - yamlEditor(): CodeMirrorPo { - return CodeMirrorPo.bySelector(this.self(), '[data-testid="yaml-editor-code-mirror"]'); + saveButton() { + return new AsyncButtonPo('[data-testid="form-save"]', this.self()); } } diff --git a/cypress/e2e/po/pages/fleet/fleet.cattle.io.clustergroup.po.ts b/cypress/e2e/po/pages/fleet/fleet.cattle.io.clustergroup.po.ts index adad51dd082..332bac73b54 100644 --- a/cypress/e2e/po/pages/fleet/fleet.cattle.io.clustergroup.po.ts +++ b/cypress/e2e/po/pages/fleet/fleet.cattle.io.clustergroup.po.ts @@ -5,14 +5,16 @@ import ResourceTablePo from '@/cypress/e2e/po/components/resource-table.po'; import FleetClusterGroupsList from '@/cypress/e2e/po/lists/fleet/fleet.cattle.io.clustergroup'; import FleetClusterGroupsCreateEditPo from '@/cypress/e2e/po/edit/fleet/fleet.cattle.io.clustergroup.po'; export class FleetClusterGroupsListPagePo extends PagePo { - static url = `/c/_/fleet/fleet.cattle.io.clustergroup` + private static createPath(clusterId: string) { + return `/c/${ clusterId }/fleet/fleet.cattle.io.clustergroup`; + } - constructor() { - super(FleetClusterGroupsListPagePo.url); + static goTo(clusterId: string): Cypress.Chainable { + return super.goTo(FleetClusterGroupsListPagePo.createPath(clusterId)); } - goTo() { - return cy.visit(FleetClusterGroupsListPagePo.url); + constructor(private clusterId = '_') { + super(FleetClusterGroupsListPagePo.createPath(clusterId)); } static navTo() { @@ -44,7 +46,7 @@ export class FleetClusterGroupsListPagePo extends PagePo { return this.self().find('[data-testid="masthead-create"]').click(); } - createFleetClusterGroupsForm(id? : string): FleetClusterGroupsCreateEditPo { - return new FleetClusterGroupsCreateEditPo(id); + createFleetClusterGroupsForm(workspace?: string, id? : string): FleetClusterGroupsCreateEditPo { + return new FleetClusterGroupsCreateEditPo(this.clusterId, workspace, id); } } diff --git a/cypress/e2e/tests/pages/fleet/cluster-groups.spec.ts b/cypress/e2e/tests/pages/fleet/cluster-groups.spec.ts index a6dcd9f3810..6f185ee44c4 100644 --- a/cypress/e2e/tests/pages/fleet/cluster-groups.spec.ts +++ b/cypress/e2e/tests/pages/fleet/cluster-groups.spec.ts @@ -1,63 +1,147 @@ import { FleetClusterGroupsListPagePo } from '@/cypress/e2e/po/pages/fleet/fleet.cattle.io.clustergroup.po'; import FleetClusterGroupDetailsPo from '@/cypress/e2e/po/detail/fleet/fleet.cattle.io.clustergroup.po'; import { HeaderPo } from '@/cypress/e2e/po/components/header.po'; +import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po'; describe('Cluster Groups', { testIsolation: 'off', tags: ['@fleet', '@adminUser'] }, () => { const fleetClusterGroups = new FleetClusterGroupsListPagePo(); const headerPo = new HeaderPo(); + const localWorkspace = 'fleet-local'; + let clusterGroupName; + let removeClusterGroups = false; + const clusterGroupsToDelete = []; - describe('List', { tags: ['@vai', '@adminUser'] }, () => { - before(() => { - cy.login(); + before(() => { + cy.login(); + cy.createE2EResourceName('cluster-group').then((name) => { + clusterGroupName = name; }); + }); - it('check table headers are available in list and details view', () => { - const groupName = 'default'; - const workspace = 'fleet-local'; + it('can create cluster group', () => { + FleetClusterGroupsListPagePo.navTo(); + fleetClusterGroups.waitForPage(); + headerPo.selectWorkspace(localWorkspace); + fleetClusterGroups.clickCreate(); + fleetClusterGroups.createFleetClusterGroupsForm().waitForPage(); - FleetClusterGroupsListPagePo.navTo(); - fleetClusterGroups.waitForPage(); - headerPo.selectWorkspace(workspace); - fleetClusterGroups.clusterGroupsList().rowWithName(groupName).checkVisible(); + fleetClusterGroups.createFleetClusterGroupsForm().nameNsDescription().name().set(clusterGroupName); + fleetClusterGroups.createFleetClusterGroupsForm().saveCreateForm().cruResource().saveOrCreate() + .click() + .then(() => { + removeClusterGroups = true; + clusterGroupsToDelete.push(`${ localWorkspace }/${ clusterGroupName }`); + }); - // check table headers - const expectedHeaders = ['State', 'Name', 'Clusters Ready', 'Resources', 'Age']; + fleetClusterGroups.waitForPage(); + fleetClusterGroups.clusterGroupsList().details(clusterGroupName, 1).should('be.visible'); + }); - fleetClusterGroups.clusterGroupsList().resourceTable().sortableTable().tableHeaderRow() - .within('.table-header-container .content') - .each((el, i) => { - expect(el.text().trim()).to.eq(expectedHeaders[i]); - }); + it('can edit a cluster group', () => { + FleetClusterGroupsListPagePo.navTo(); + fleetClusterGroups.waitForPage(); + headerPo.selectWorkspace(localWorkspace); + fleetClusterGroups.clusterGroupsList().actionMenu(clusterGroupName).getMenuItem('Edit Config').click(); + fleetClusterGroups.createFleetClusterGroupsForm(localWorkspace, clusterGroupName).waitForPage('mode=edit'); + fleetClusterGroups.createFleetClusterGroupsForm().nameNsDescription().description().set(`${ clusterGroupName }-fleet-desc`); + fleetClusterGroups.createFleetClusterGroupsForm().saveCreateForm().cruResource().saveAndWaitForRequests('PUT', `v1/fleet.cattle.io.clustergroups/${ localWorkspace }/${ clusterGroupName }`) + .then(({ response }) => { + expect(response?.statusCode).to.eq(200); + expect(response?.body.metadata).to.have.property('name', clusterGroupName); + expect(response?.body.metadata.annotations).to.have.property('field.cattle.io/description', `${ clusterGroupName }-fleet-desc`); + }); + fleetClusterGroups.waitForPage(); + }); - // go to fleet cluster details - fleetClusterGroups.goToDetailsPage(groupName); + it('can clone a cluster group', () => { + FleetClusterGroupsListPagePo.navTo(); + fleetClusterGroups.waitForPage(); + headerPo.selectWorkspace(localWorkspace); + fleetClusterGroups.clusterGroupsList().actionMenu(clusterGroupName).getMenuItem('Clone').click(); + fleetClusterGroups.createFleetClusterGroupsForm(localWorkspace, clusterGroupName).waitForPage('mode=clone'); + fleetClusterGroups.createFleetClusterGroupsForm().nameNsDescription().name().set(`clone-${ clusterGroupName }`); + fleetClusterGroups.createFleetClusterGroupsForm().nameNsDescription().description().set(`${ clusterGroupName }-fleet-desc`); + fleetClusterGroups.createFleetClusterGroupsForm().saveCreateForm().cruResource().saveAndWaitForRequests('POST', 'v1/fleet.cattle.io.clustergroups') + .then(({ response }) => { + expect(response?.statusCode).to.eq(201); + removeClusterGroups = true; + clusterGroupsToDelete.push(`${ localWorkspace }/clone-${ clusterGroupName }`); + expect(response?.body.metadata).to.have.property('name', `clone-${ clusterGroupName }`); + expect(response?.body.metadata.annotations).to.have.property('field.cattle.io/description', `${ clusterGroupName }-fleet-desc`); + }); + fleetClusterGroups.waitForPage(); + fleetClusterGroups.clusterGroupsList().details(`clone-${ clusterGroupName }`, 1).should('be.visible'); + }); - const fleetClusterGroupDetailsPage = new FleetClusterGroupDetailsPo(workspace, groupName); + it('can delete cluster group', () => { + FleetClusterGroupsListPagePo.navTo(); + fleetClusterGroups.waitForPage(); + headerPo.selectWorkspace(localWorkspace); + fleetClusterGroups.clusterGroupsList().actionMenu(clusterGroupName).getMenuItem('Delete').click(); + fleetClusterGroups.clusterGroupsList().resourceTable().sortableTable().rowNames('.col-link-detail') + .then((rows: any) => { + const promptRemove = new PromptRemove(); - fleetClusterGroupDetailsPage.waitForPage(null, 'clusters'); + cy.intercept('DELETE', `v1/fleet.cattle.io.clustergroups/${ localWorkspace }/clone-${ clusterGroupName }`).as('deleteClusterGroup'); - // check table headers - const expectedHeadersDetailsView = ['State', 'Name', 'Bundles Ready', 'Repos Ready', 'Resources', 'Last Seen', 'Age']; + promptRemove.remove(); + cy.wait('@deleteClusterGroup'); + fleetClusterGroups.waitForPage(); + fleetClusterGroups.clusterGroupsList().resourceTable().sortableTable().checkRowCount(false, rows.length - 1); + fleetClusterGroups.clusterGroupsList().resourceTable().sortableTable().rowNames('.col-link-detail') + .should('not.contain', `clone-${ clusterGroupName }`); + }); + }); - fleetClusterGroupDetailsPage.clusterList().resourceTable().sortableTable() - .tableHeaderRow() - .within('.table-header-container .content') - .each((el, i) => { - expect(el.text().trim()).to.eq(expectedHeadersDetailsView[i]); - }); - }); + // testing https://github.com/rancher/dashboard/issues/11687 + it('can open "Edit as YAML"', () => { + FleetClusterGroupsListPagePo.navTo(); + fleetClusterGroups.waitForPage(); + fleetClusterGroups.clickCreate(); + fleetClusterGroups.createFleetClusterGroupsForm().saveCreateForm().createEditView().editAsYaml(); + fleetClusterGroups.createFleetClusterGroupsForm().saveCreateForm().resourceYaml().codeMirror() + .checkExists(); }); - describe('Edit', { tags: ['@vai', '@adminUser'] }, () => { - before(() => { - cy.login(); - }); - it('can open "Edit as YAML"', () => { - FleetClusterGroupsListPagePo.navTo(); - fleetClusterGroups.waitForPage(); - fleetClusterGroups.clickCreate(); - fleetClusterGroups.createFleetClusterGroupsForm().editAsYaml().click(); - fleetClusterGroups.createFleetClusterGroupsForm().yamlEditor().checkExists(); - }); + it('check table headers are available in list and details view', { tags: ['@vai', '@adminUser'] }, () => { + const groupName = 'default'; + + FleetClusterGroupsListPagePo.navTo(); + fleetClusterGroups.waitForPage(); + headerPo.selectWorkspace(localWorkspace); + fleetClusterGroups.clusterGroupsList().rowWithName(groupName).checkVisible(); + + // check table headers + const expectedHeaders = ['State', 'Name', 'Clusters Ready', 'Resources', 'Age']; + + fleetClusterGroups.clusterGroupsList().resourceTable().sortableTable().tableHeaderRow() + .within('.table-header-container .content') + .each((el, i) => { + expect(el.text().trim()).to.eq(expectedHeaders[i]); + }); + + // go to fleet cluster details + fleetClusterGroups.goToDetailsPage(groupName); + + const fleetClusterGroupDetailsPage = new FleetClusterGroupDetailsPo(localWorkspace, groupName); + + fleetClusterGroupDetailsPage.waitForPage(null, 'clusters'); + + // check table headers + const expectedHeadersDetailsView = ['State', 'Name', 'Bundles Ready', 'Repos Ready', 'Resources', 'Last Seen', 'Age']; + + fleetClusterGroupDetailsPage.clusterList().resourceTable().sortableTable() + .tableHeaderRow() + .within('.table-header-container .content') + .each((el, i) => { + expect(el.text().trim()).to.eq(expectedHeadersDetailsView[i]); + }); + }); + + after(() => { + if (removeClusterGroups) { + // delete gitrepo + clusterGroupsToDelete.forEach((r) => cy.deleteRancherResource('v1', 'fleet.cattle.io.clustergroups', r, false)); + } }); }); diff --git a/cypress/e2e/tests/pages/fleet/dashboard.spec.ts b/cypress/e2e/tests/pages/fleet/dashboard.spec.ts index 32125926db4..5cd98f60401 100644 --- a/cypress/e2e/tests/pages/fleet/dashboard.spec.ts +++ b/cypress/e2e/tests/pages/fleet/dashboard.spec.ts @@ -3,7 +3,7 @@ import FleetGitRepoDetailsPo from '@/cypress/e2e/po/detail/fleet/fleet.cattle.io import { GitRepoCreatePo } from '@/cypress/e2e/po/pages/fleet/gitrepo-create.po'; import { GitRepoEditPo } from '@/cypress/e2e/po/edit/fleet/gitrepo-edit.po'; import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po'; -import { LONG_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; +import { LONG_TIMEOUT_OPT, MEDIUM_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; import { gitRepoTargetAllClustersRequest } from '@/cypress/e2e/blueprints/fleet/gitrepos'; import { HeaderPo } from '@/cypress/e2e/po/components/header.po'; import { MenuActions } from '@/cypress/support/types/menu-actions'; @@ -118,11 +118,14 @@ describe('Fleet Dashboard', { tags: ['@fleet', '@adminUser', '@jenkins'] }, () = it('can clone a git repo', () => { const gitRepoEditPage = new GitRepoEditPo(localWorkspace, repoName); + cy.intercept('GET', '/v1/secrets?exclude=metadata.managedFields').as('getSecrets'); + fleetDashboardPage.goTo(); fleetDashboardPage.waitForPage(); fleetDashboardPage.sortableTable().rowActionMenuOpen(repoName).getMenuItem('Clone').click(); gitRepoEditPage.waitForPage('mode=clone'); + cy.wait('@getSecrets', MEDIUM_TIMEOUT_OPT).its('response.statusCode').should('eq', 200); gitRepoEditPage.title().contains(`Git Repo: Clone from ${ repoName }`).should('be.visible'); headerPo.selectWorkspace('fleet-default'); gitRepoEditPage.nameNsDescription().name().set(`clone-${ repoName }`);