From 3c8e3b15000df403e6af5ac0c099d2c100a10218 Mon Sep 17 00:00:00 2001 From: Yonas Berhe Date: Wed, 11 Dec 2024 06:56:26 -0800 Subject: [PATCH] automation: fleet dashboard tests --- cypress/e2e/po/components/header.po.ts | 6 + cypress/e2e/po/edit/fleet/gitrepo-edit.po.ts | 65 +++++ .../e2e/po/pages/fleet/fleet-dashboard.po.ts | 17 ++ .../e2e/tests/pages/fleet/dashboard.spec.ts | 232 ++++++++++++++---- cypress/support/types/menu-actions.ts | 3 + 5 files changed, 281 insertions(+), 42 deletions(-) create mode 100644 cypress/e2e/po/edit/fleet/gitrepo-edit.po.ts diff --git a/cypress/e2e/po/components/header.po.ts b/cypress/e2e/po/components/header.po.ts index 1915f0e4d7c..1888f5ebdd7 100644 --- a/cypress/e2e/po/components/header.po.ts +++ b/cypress/e2e/po/components/header.po.ts @@ -28,6 +28,12 @@ export class HeaderPo extends ComponentPo { return wsFilter.clickOptionWithLabel(name); } + checkCurrentWorkspace(name: string) { + const wsFilter = new WorkspaceSwitcherPo(); + + return wsFilter.checkOptionSelected(name); + } + importYamlHeaderAction() { return this.self().find('[data-testid="header-action-import-yaml"]'); } diff --git a/cypress/e2e/po/edit/fleet/gitrepo-edit.po.ts b/cypress/e2e/po/edit/fleet/gitrepo-edit.po.ts new file mode 100644 index 00000000000..93bf3c2b20d --- /dev/null +++ b/cypress/e2e/po/edit/fleet/gitrepo-edit.po.ts @@ -0,0 +1,65 @@ +import PagePo from '@/cypress/e2e/po/pages/page.po'; +import ArrayListPo from '@/cypress/e2e/po/components/array-list.po'; +import CreateEditViewPo from '@/cypress/e2e/po/components/create-edit-view.po'; +import LabeledInputPo from '@/cypress/e2e/po/components/labeled-input.po'; +import LabeledSelectPo from '@/cypress/e2e/po/components/labeled-select.po'; +import SelectOrCreateAuthPo from '@/cypress/e2e/po/components/select-or-create-auth.po'; +import NameNsDescription from '@/cypress/e2e/po/components/name-ns-description.po'; + +export class GitRepoEditPo extends PagePo { + private static createPath(fleetWorkspace: string, gitRepoName: string) { + return `/c/_/fleet/fleet.cattle.io.gitrepo/${ fleetWorkspace }/${ gitRepoName }`; + } + + static goTo(path: string): Cypress.Chainable { + throw new Error('invalid'); + } + + constructor(fleetWorkspace: string, gitRepoName: string) { + super(GitRepoEditPo.createPath(fleetWorkspace, gitRepoName)); + } + + title() { + return this.self().get('.title .primaryheader h1'); + } + + nameNsDescription() { + return new NameNsDescription(this.self()); + } + + setBranchName(branch = 'dashboard-e2e-basic') { + return LabeledInputPo.byLabel(this.self(), 'Branch').set(branch); + } + + setGitRepoUrl(url: string) { + return LabeledInputPo.byLabel(this.self(), 'Repository URL').set(url); + } + + setHelmRepoURLRegex(regexStr = 'https://charts.rancher.io/*') { + return LabeledInputPo.bySelector(this.self(), '[data-testid="gitrepo-helm-repo-url-regex"]').set(regexStr); + } + + setGitRepoPath(path: string, index = 0) { + return this.gitRepoPaths().setValueAtIndex(path, index); + } + + targetCluster(): LabeledSelectPo { + return new LabeledSelectPo('[data-testid="fleet-gitrepo-target-cluster"]'); + } + + footer() { + return new CreateEditViewPo(this.self()); + } + + gitRepoPaths() { + return new ArrayListPo('[data-testid="gitRepo-paths"]'); + } + + authSelectOrCreate(selector: string) { + return new SelectOrCreateAuthPo(selector); + } + + helmAuthSelectOrCreate() { + return this.authSelectOrCreate('[data-testid="gitrepo-helm-auth"]'); + } +} diff --git a/cypress/e2e/po/pages/fleet/fleet-dashboard.po.ts b/cypress/e2e/po/pages/fleet/fleet-dashboard.po.ts index be82a80b991..e2a3699d08a 100644 --- a/cypress/e2e/po/pages/fleet/fleet-dashboard.po.ts +++ b/cypress/e2e/po/pages/fleet/fleet-dashboard.po.ts @@ -2,6 +2,7 @@ import PagePo from '@/cypress/e2e/po/pages/page.po'; import ResourceTablePo from '@/cypress/e2e/po/components/resource-table.po'; import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po'; import { LONG_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; +import BaseResourceList from '@/cypress/e2e/po/lists/base-resource-list.po'; export class FleetDashboardPagePo extends PagePo { static url: string; @@ -44,4 +45,20 @@ export class FleetDashboardPagePo extends PagePo { sortableTable(tableName = 'fleet-local') { return this.resourceTable(tableName).sortableTable(); } + + goToGitRepoListLink(name: 'fleet-local' | 'fleet-default') { + return this.self().find(`[data-testid="collapsible-card-${ name }"] h2 span` ); + } + + list() { + return new BaseResourceList('[data-testid="sortable-table-list-container"]'); + } + + fleetDashboardEmptyState() { + return this.self().get('.fleet-empty-dashboard'); + } + + getStartedButton() { + return this.self().get('.btn').contains('Get started'); + } } diff --git a/cypress/e2e/tests/pages/fleet/dashboard.spec.ts b/cypress/e2e/tests/pages/fleet/dashboard.spec.ts index 8e8401a176f..32125926db4 100644 --- a/cypress/e2e/tests/pages/fleet/dashboard.spec.ts +++ b/cypress/e2e/tests/pages/fleet/dashboard.spec.ts @@ -1,65 +1,213 @@ import { FleetDashboardPagePo } from '@/cypress/e2e/po/pages/fleet/fleet-dashboard.po'; -// import { GitRepoCreatePo } from '@/cypress/e2e/po/pages/fleet/gitrepo-create.po'; -// import BurgerMenuPo from '@/cypress/e2e/po/side-bars/burger-side-menu.po'; -// import { LONG_TIMEOUT_OPT } from '@/cypress/support/utils/timeouts'; - -describe('Fleet Dashboard', { tags: ['@fleet', '@adminUser'] }, () => { - let fleetDashboardPage: FleetDashboardPagePo; - // const repoName = 'fleet-e2e-test-dashboard'; - - // Note - The 'describe` previously had `.only`, which ironically meant this was not tested in our CI (probably something to so with grep tags) - // Enabling the test results results in consistent failures (bundle does not become ready). For the short term comment these out +import FleetGitRepoDetailsPo from '@/cypress/e2e/po/detail/fleet/fleet.cattle.io.gitrepo.po'; +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 { gitRepoTargetAllClustersRequest } from '@/cypress/e2e/blueprints/fleet/gitrepos'; +import { HeaderPo } from '@/cypress/e2e/po/components/header.po'; +import { MenuActions } from '@/cypress/support/types/menu-actions'; +import * as path from 'path'; +import * as jsyaml from 'js-yaml'; +import { FleetGitRepoListPagePo } from '@/cypress/e2e/po/pages/fleet/fleet.cattle.io.gitrepo.po'; +const downloadsFolder = Cypress.config('downloadsFolder'); + +describe('Fleet Dashboard', { tags: ['@fleet', '@adminUser', '@jenkins'] }, () => { + const fleetDashboardPage = new FleetDashboardPagePo('_'); + const gitRepoCreatePage = new GitRepoCreatePo('_'); + const headerPo = new HeaderPo(); + + let repoName; + const gitRepoUrl = 'https://github.com/rancher/fleet-test-data'; + const branch = 'master'; + const paths = 'qa-test-apps/nginx-app'; + const localWorkspace = 'fleet-local'; + let removeGitRepo = false; + const reposToDelete = []; beforeEach(() => { cy.login(); - fleetDashboardPage = new FleetDashboardPagePo('_'); - fleetDashboardPage.goTo(); + cy.createE2EResourceName('git-repo').then((name) => { + repoName = name; + }); }); it('has the correct title', () => { - cy.get('.fleet-empty-dashboard').should('be.visible'); + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + + fleetDashboardPage.fleetDashboardEmptyState().should('be.visible'); cy.title().should('eq', 'Rancher - Continuous Delivery - Dashboard'); }); - // before(() => { - // cy.login(); + it('Get Started button takes you to the correct page', () => { + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); - // const gitRepoCreatePage = new GitRepoCreatePo('_'); + fleetDashboardPage.fleetDashboardEmptyState().should('be.visible'); + fleetDashboardPage.getStartedButton().click(); + gitRepoCreatePage.waitForPage(); + gitRepoCreatePage.title().contains('Git Repo: Create').should('be.visible'); + }); - // gitRepoCreatePage.goTo(); + it('Should display cluster status', () => { + // create gitrepo + cy.createRancherResource('v1', 'fleet.cattle.io.gitrepos', gitRepoTargetAllClustersRequest(localWorkspace, repoName, gitRepoUrl, branch, paths)).then(() => { + removeGitRepo = true; + reposToDelete.push(`fleet-local/${ repoName }`); + }); - // gitRepoCreatePage.setRepoName(repoName); - // gitRepoCreatePage.selectWorkspace('fleet-local'); - // gitRepoCreatePage.setGitRepoUrl('https://github.com/rancher/fleet-test-data.git'); - // gitRepoCreatePage.setBranchName(); - // // NB - This step is here because DOM may not be ready - // gitRepoCreatePage.goToNext(); - // gitRepoCreatePage.create(); - // }); + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); - // it('Should display cluster status', () => { - // // check if burguer menu nav is highlighted correctly for Fleet - // BurgerMenuPo.checkIfMenuItemLinkIsHighlighted('Continuous Delivery'); + // check if burguer menu nav is highlighted correctly for Fleet + BurgerMenuPo.checkIfMenuItemLinkIsHighlighted('Continuous Delivery'); - // const row = fleetDashboardPage.sortableTable('fleet-local').row(0); + const row = fleetDashboardPage.sortableTable(localWorkspace).row(0); - // row.get('.bg-success[data-testid="clusters-ready"]', LONG_TIMEOUT_OPT).should('exist'); - // row.get('.bg-success[data-testid="clusters-ready"] span').should('have.text', '1/1'); + row.get('.bg-success[data-testid="clusters-ready"]', LONG_TIMEOUT_OPT).should('exist'); + row.get('.bg-success[data-testid="clusters-ready"] span').should('have.text', '1/1'); - // row.get('.bg-success[data-testid="bundles-ready"]').should('exist'); - // row.get('.bg-success[data-testid="bundles-ready"] span').should('have.text', '1/1'); + row.get('.bg-success[data-testid="bundles-ready"]').should('exist'); + row.get('.bg-success[data-testid="bundles-ready"] span').should('have.text', '1/1'); - // row.get('.bg-success[data-testid="resources-ready"]').should('exist'); - // row.get('.bg-success[data-testid="resources-ready"] span').should('have.text', '1/1'); - // }); + row.get('.bg-success[data-testid="resources-ready"]').should('exist'); + row.get('.bg-success[data-testid="resources-ready"] span').should('have.text', '1/1'); + }); - // after(() => { - // fleetDashboardPage = new FleetDashboardPagePo('_'); - // fleetDashboardPage.goTo(); + it('can navigate to Git Repo details page from Fleet Dashboard', () => { + const gitRepoDetails = new FleetGitRepoDetailsPo(localWorkspace, repoName); - // const fleetLocalResourceTable = fleetDashboardPage.resourceTable('fleet-local'); + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.list().rowWithName(repoName).column(0).find('a') + .click(); + gitRepoDetails.waitForPage(null, 'bundles'); + }); + + it('should only display action menu with allowed actions only', () => { + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + headerPo.selectWorkspace(localWorkspace); + + const constActionMenu = fleetDashboardPage.sortableTable().rowActionMenuOpen(repoName); + + const allowedActions: MenuActions[] = [ + MenuActions.Pause, + MenuActions.ForceUpdate, + MenuActions.EditYaml, + MenuActions.EditConfig, + MenuActions.Clone, + MenuActions.DownloadYaml, + MenuActions.Delete + ]; + + const disabledActions: MenuActions[] = [MenuActions.ChangeWorkspace]; + + allowedActions.forEach((action) => { + constActionMenu.getMenuItem(action).should('exist'); + }); + + // Disabled actions should not exist + disabledActions.forEach((action) => { + constActionMenu.getMenuItem(action).should('not.exist'); + }); + }); + + it('can clone a git repo', () => { + const gitRepoEditPage = new GitRepoEditPo(localWorkspace, repoName); + + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.sortableTable().rowActionMenuOpen(repoName).getMenuItem('Clone').click(); + + gitRepoEditPage.waitForPage('mode=clone'); + gitRepoEditPage.title().contains(`Git Repo: Clone from ${ repoName }`).should('be.visible'); + headerPo.selectWorkspace('fleet-default'); + gitRepoEditPage.nameNsDescription().name().set(`clone-${ repoName }`); + gitRepoEditPage.footer().nextPage(); + gitRepoEditPage.footer().create().then(() => { + removeGitRepo = true; + reposToDelete.push(`fleet-default/clone-${ repoName }`); + }); + + FleetDashboardPagePo.navTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.sortableTable('fleet-default').rowElementWithName(`clone-${ repoName }`).should('be.visible'); + fleetDashboardPage.sortableTable('fleet-local').rowElementWithName(repoName).should('be.visible'); + }); + + it('user lands in correct git repo workspace when using workspace link on Fleet Dashboard', () => { + const gitrepoListPage = new FleetGitRepoListPagePo(); + + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.sortableTable('fleet-default').rowElementWithName(`clone-${ repoName }`).should('be.visible'); + fleetDashboardPage.sortableTable('fleet-local').rowElementWithName(repoName).should('be.visible'); - // fleetLocalResourceTable.sortableTable().deleteItemWithUI(repoName); - // }); + // click workspace link: fleet default + fleetDashboardPage.goToGitRepoListLink('fleet-default').click(); + gitrepoListPage.waitForPage(); + headerPo.checkCurrentWorkspace('fleet-default'); + + // click workspace link: fleet local + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.goToGitRepoListLink('fleet-local').click(); + gitrepoListPage.waitForPage(); + headerPo.checkCurrentWorkspace('fleet-local'); + }); + + it('can Edit Yaml', () => { + const gitRepoEditPage = new GitRepoEditPo(localWorkspace, repoName); + + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.sortableTable().rowActionMenuOpen(repoName).getMenuItem('Edit YAML').click(); + gitRepoEditPage.waitForPage('mode=edit&as=yaml'); + gitRepoEditPage.title().contains(`Git Repo: ${ repoName }`).should('be.visible'); + }); + + it('can Download Yaml', () => { + cy.deleteDownloadsFolder(); + + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.sortableTable().rowActionMenuOpen(repoName).getMenuItem('Download YAML').click(); + + const downloadedFilename = path.join(downloadsFolder, `${ repoName }.yaml`); + + cy.readFile(downloadedFilename).then((buffer) => { + const obj: any = jsyaml.load(buffer); + + // Basic checks on the downloaded YAML + expect(obj.kind).to.equal('GitRepo'); + expect(obj.metadata['name']).to.equal(repoName); + expect(obj.metadata['namespace']).to.equal(localWorkspace); + expect(obj.spec['repo']).to.equal(gitRepoUrl); + }); + }); + + it('can Edit Config', () => { + const gitRepoEditPage = new GitRepoEditPo(localWorkspace, repoName); + const description = `${ repoName }-desc`; + + fleetDashboardPage.goTo(); + fleetDashboardPage.waitForPage(); + fleetDashboardPage.sortableTable().rowActionMenuOpen(repoName).getMenuItem('Edit Config').click(); + + gitRepoEditPage.waitForPage('mode=edit'); + gitRepoEditPage.nameNsDescription().description().set(description); + gitRepoEditPage.footer().nextPage(); + gitRepoEditPage.footer().save(); + fleetDashboardPage.waitForPage(); + }); + + after(() => { + if (removeGitRepo) { + // delete gitrepo + reposToDelete.forEach((r) => cy.deleteRancherResource('v1', 'fleet.cattle.io.gitrepo', r)); + } + }); }); diff --git a/cypress/support/types/menu-actions.ts b/cypress/support/types/menu-actions.ts index 72c1b46d001..9ea6fe0c67c 100644 --- a/cypress/support/types/menu-actions.ts +++ b/cypress/support/types/menu-actions.ts @@ -8,4 +8,7 @@ export enum MenuActions { ViewInApi = 'View in API', // eslint-disable-line no-unused-vars ChangeWorkspace = 'Change workspace', // eslint-disable-line no-unused-vars Delete = 'Delete', // eslint-disable-line no-unused-vars + Clone = 'Clone', // eslint-disable-line no-unused-vars + DownloadYaml = 'Download YAML', // eslint-disable-line no-unused-vars + }