From e31aebe14cfe450357085be23951c395093e9a8a Mon Sep 17 00:00:00 2001 From: Thomas Decaux Date: Thu, 28 Nov 2024 18:52:20 +0100 Subject: [PATCH] fix(ui): update ui e2e tests (#14619) Signed-off-by: ebuildy --- ui-test/.env | 9 ++++++ ui-test/src/Configuration.ts | 5 ++- ui-test/src/Constants.ts | 2 +- ui-test/src/UiTestUtilities.ts | 2 +- .../applications-list/applications-list.ts | 31 ++++++++----------- ui-test/src/auth/login-page.ts | 28 +++++++++++++++++ ui-test/src/navigation.ts | 15 ++++++--- ui-test/src/test001.ts | 4 +++ ui-test/src/test002.ts | 7 +++++ 9 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 ui-test/src/auth/login-page.ts diff --git a/ui-test/.env b/ui-test/.env index 9e4c5b3d72..4c2aa2475a 100644 --- a/ui-test/.env +++ b/ui-test/.env @@ -21,6 +21,15 @@ IS_HEADLESS=true # URL of the ArgoCD UI to test against ARGOCD_URL=http://localhost:4000 # +# argocd app definition namespace +ARGOCD_NAMESPACE=argocd-e2e +# +# argocd credentials (if any) +#ARGOCD_AUTH_USERNAME=admin +# +# argocd credentials (if any) +#ARGOCD_AUTH_PASSWORD=password +# # Git repository where applications reside GIT_REPO=https://github.com/argoproj/argocd-example-apps # diff --git a/ui-test/src/Configuration.ts b/ui-test/src/Configuration.ts index 33323433f1..74fdd20f75 100644 --- a/ui-test/src/Configuration.ts +++ b/ui-test/src/Configuration.ts @@ -1,4 +1,4 @@ -require('dotenv').config({path: __dirname + '/.env'}); +require('dotenv').config({path: __dirname + '/../.env'}); export default class Configuration { // Test specific @@ -6,6 +6,9 @@ export default class Configuration { public static readonly TEST_TIMEOUT: string | undefined = process.env.TEST_TIMEOUT; // ArgoCD UI specific. These are for single application-based tests, so one can quickly create an app based on the environment variables public static readonly ARGOCD_URL: string = process.env.ARGOCD_URL ? process.env.ARGOCD_URL : ''; + public static readonly ARGOCD_NAMESPACE: string = process.env.ARGOCD_NAMESPACE || 'argocd'; + public static readonly ARGOCD_AUTH_USERNAME: string = process.env.ARGOCD_AUTH_USERNAME || ''; + public static readonly ARGOCD_AUTH_PASSWORD: string = process.env.ARGOCD_AUTH_PASSWORD || ''; public static readonly APP_NAME: string = process.env.APP_NAME ? process.env.APP_NAME : ''; public static readonly APP_PROJECT: string = process.env.APP_PROJECT ? process.env.APP_PROJECT : ''; public static readonly GIT_REPO: string = process.env.GIT_REPO ? process.env.GIT_REPO : ''; diff --git a/ui-test/src/Constants.ts b/ui-test/src/Constants.ts index 89c1155774..f3f12dce52 100644 --- a/ui-test/src/Constants.ts +++ b/ui-test/src/Constants.ts @@ -1,4 +1,4 @@ export const TEST_TIMEOUT: number = 60000; -export const TEST_SLIDING_PANEL_TIMEOUT: number = 6000; +export const TEST_SLIDING_PANEL_TIMEOUT: number = 10000; export const TEST_IS_NOT_VISIBLE_TIMEOUT: number = 5000; export const ENABLE_CONSOLE_LOG: boolean = true; diff --git a/ui-test/src/UiTestUtilities.ts b/ui-test/src/UiTestUtilities.ts index d66eaaed4c..ac38790ca1 100644 --- a/ui-test/src/UiTestUtilities.ts +++ b/ui-test/src/UiTestUtilities.ts @@ -80,7 +80,7 @@ export default class UiTestUtilities { timeout = parseInt(Configuration.TEST_TIMEOUT, 10); } const element = await driver.wait(until.elementLocated(locator), timeout); - var isDisplayed = await element.isDisplayed(); + const isDisplayed = await element.isDisplayed(); if (isDisplayed) { await driver.wait(until.elementIsVisible(element), timeout); } diff --git a/ui-test/src/applications-list/applications-list.ts b/ui-test/src/applications-list/applications-list.ts index 3aa5e42ab2..ae76b9d80c 100644 --- a/ui-test/src/applications-list/applications-list.ts +++ b/ui-test/src/applications-list/applications-list.ts @@ -5,6 +5,7 @@ import {Base} from '../base'; import {ApplicationCreatePanel} from '../application-create-panel/application-create-panel'; import {ApplicationsSyncPanel, SYNC_PANEL_SYNCHRONIZE_BUTTON} from '../applications-sync-panel/applications-sync-panel'; import {PopupManager} from '../popup/popup-manager'; +import Configuration from '../Configuration'; const NEW_APP_BUTTON: By = By.xpath('.//button[@qe-id="applications-list-button-new-app"]'); // Uncomment to use: @@ -155,45 +156,39 @@ export class ApplicationsList extends Base { // Locators - // By.css('#app .applications-tiles .applications-list-" + appName + "''); + // By.css('#app .applications-tiles .applications-list-argocd_" + appName + "''); + + private getApplicationTileSelector(appName: string): string { + return './/div[contains(@class,"qe-applications-list-' + Configuration.ARGOCD_NAMESPACE + '_' + appName + '")]'; + } private getApplicationTileLocator(appName: string): By { - return By.xpath('.//div[contains(@class,"qe-applications-list-"' + appName + ')'); + return By.xpath(this.getApplicationTileSelector(appName)); } private getSyncButtonLocatorForApp(appName: string): By { - return By.xpath('.//div[contains(@class, "qe-applications-list-' + appName + '")]//div[@class="row"]//ancestor::a[@qe-id="applications-tiles-button-sync"]'); + return By.xpath(this.getApplicationTileSelector(appName) + '//div[@class="row"]//ancestor::a[@qe-id="applications-tiles-button-sync"]'); } private getDeleteButtonLocatorForApp(appName: string): By { - return By.xpath('.//div[contains(@class, "qe-applications-list-' + appName + '")]//div[@class="row"]//ancestor::a[@qe-id="applications-tiles-button-delete"]'); + return By.xpath(this.getApplicationTileSelector(appName) + '//div[@class="row"]//ancestor::a[@qe-id="applications-tiles-button-delete"]'); } private getRefreshButtonLocatorForApp(appName: string): By { - return By.xpath('.//div[contains(@class, "qe-applications-list-' + appName + '")]//div[@class="row"]//ancestor::a[@qe-id="applications-tiles-button-refresh"]'); + return By.xpath(this.getApplicationTileSelector(appName) + '//div[@class="row"]//ancestor::a[@qe-id="applications-tiles-button-refresh"]'); } private getApplicationHealthTitle(appName: string): By { - return By.xpath( - './/div[contains(@class, "qe-applications-list-' + - appName + - '")]//div[@class="row"]//div[@qe-id="applications-tiles-health-status"]//i[@qe-id="utils-health-status-title"]' - ); + return By.xpath(this.getApplicationTileSelector(appName) + '//div[@class="row"]//div[@qe-id="applications-tiles-health-status"]//i[@qe-id="utils-health-status-title"]'); } private getApplicationSyncTitle(appName: string): By { - return By.xpath( - './/div[contains(@class, "qe-applications-list-' + - appName + - '")]//div[@class="row"]//div[@qe-id="applications-tiles-health-status"]//i[@qe-id="utils-sync-status-title"]' - ); + return By.xpath(this.getApplicationTileSelector(appName) + '//div[@class="row"]//div[@qe-id="applications-tiles-health-status"]//i[@qe-id="utils-sync-status-title"]'); } private getApplicationOperationsTitle(appName: string): By { return By.xpath( - './/div[contains(@class, "qe-applications-list-' + - appName + - '")]//div[@class="row"]//div[@qe-id="applications-tiles-health-status"]//i[@qe-id="utils-operations-status-title"]' + this.getApplicationTileSelector(appName) + '//div[@class="row"]//div[@qe-id="applications-tiles-health-status"]//i[@qe-id="utils-operations-status-title"]' ); } } diff --git a/ui-test/src/auth/login-page.ts b/ui-test/src/auth/login-page.ts new file mode 100644 index 0000000000..29ff205cfa --- /dev/null +++ b/ui-test/src/auth/login-page.ts @@ -0,0 +1,28 @@ +import {By, WebDriver} from 'selenium-webdriver'; +import {Base} from '../base'; +import Configuration from '../Configuration'; +import UiTestUtilities from '../UiTestUtilities'; + +const LOGIN_FORM: By = By.css('#app .login__box form'); +const LOGIN_FORM_INPUT: By = By.css('input.argo-field'); +const LOGIN_FORM_BUTTON: By = By.css('button.argo-button'); + +export class AuthLoginPage extends Base { + public constructor(driver: WebDriver) { + super(driver); + } + + /** + * Fill login form and submit it + */ + public async loginWithCredentials() { + const loginForm = await UiTestUtilities.findUiElement(this.driver, LOGIN_FORM); + const inputs = await loginForm.findElements(LOGIN_FORM_INPUT); + const submitButton = await loginForm.findElement(LOGIN_FORM_BUTTON); + + await inputs[0].sendKeys(Configuration.ARGOCD_AUTH_USERNAME); + await inputs[1].sendKeys(Configuration.ARGOCD_AUTH_PASSWORD); + + await submitButton.click(); + } +} diff --git a/ui-test/src/navigation.ts b/ui-test/src/navigation.ts index 57588b86d4..8baaff37e4 100644 --- a/ui-test/src/navigation.ts +++ b/ui-test/src/navigation.ts @@ -2,18 +2,25 @@ import {By, WebDriver} from 'selenium-webdriver'; import {ApplicationsList} from './applications-list/applications-list'; import UiTestUtilities from './UiTestUtilities'; import {Base} from './base'; +import {AuthLoginPage} from './auth/login-page'; -const NAVBAR_APPLICATIONS_BUTTON: By = By.css('#app .nav-bar .argo-icon-application'); -const NAVBAR_SETTINGS_BUTTON: By = By.css('#app .nav-bar .argo-icon-settings'); -const NAVBAR_USER_INFO_BUTTON: By = By.css('#app .nav-bar .fa-user-circle'); -const NAVBAR_DOCS_BUTTON: By = By.css('#app .nav-bar .argo-icon-docs'); +const NAVBAR_APPLICATIONS_BUTTON: By = By.css('#app .sidebar .argo-icon-application'); +const NAVBAR_SETTINGS_BUTTON: By = By.css('#app .sidebar .argo-icon-settings'); +const NAVBAR_USER_INFO_BUTTON: By = By.css('#app .sidebar .fa-user-circle'); +const NAVBAR_DOCS_BUTTON: By = By.css('#app .sidebar .argo-icon-docs'); export class Navigation extends Base { private applicationsList: ApplicationsList; + private authLoginPage: AuthLoginPage; public constructor(driver: WebDriver) { super(driver); this.applicationsList = new ApplicationsList(this.driver); + this.authLoginPage = new AuthLoginPage(this.driver); + } + + public getLoginPage(): AuthLoginPage { + return this.authLoginPage; } /** diff --git a/ui-test/src/test001.ts b/ui-test/src/test001.ts index 3db3f4d714..4c2fa604e3 100644 --- a/ui-test/src/test001.ts +++ b/ui-test/src/test001.ts @@ -19,6 +19,10 @@ import {PopupManager} from './popup/popup-manager'; async function doTest() { const navigation = await UiTestUtilities.init(); try { + if (Configuration.ARGOCD_AUTH_USERNAME !== '') { + await navigation.getLoginPage().loginWithCredentials(); + } + const appsList: ApplicationsList = await navigation.clickApplicationsNavBarButton(); const applicationCreatePanel: ApplicationCreatePanel = await appsList.clickNewAppButton(); diff --git a/ui-test/src/test002.ts b/ui-test/src/test002.ts index 4e1f41fc05..f1c9e56225 100644 --- a/ui-test/src/test002.ts +++ b/ui-test/src/test002.ts @@ -2,6 +2,7 @@ import UiTestUtilities from './UiTestUtilities'; import {trace} from 'console'; import {ApplicationsList} from './applications-list/applications-list'; import {ApplicationCreatePanel} from './application-create-panel/application-create-panel'; +import Configuration from './Configuration'; /** * Test to demo how to visit each page via the navigation bar on the left. @@ -10,11 +11,17 @@ import {ApplicationCreatePanel} from './application-create-panel/application-cre async function doTest() { const navigation = await UiTestUtilities.init(); try { + if (Configuration.ARGOCD_AUTH_USERNAME !== '') { + await navigation.getLoginPage().loginWithCredentials(); + } + await navigation.clickDocsNavBarButton(); await navigation.clickUserInfoNavBarButton(); await navigation.clickSettingsNavBarButton(); const appsList: ApplicationsList = await navigation.clickApplicationsNavBarButton(); const applicationCreatePanel: ApplicationCreatePanel = await appsList.clickNewAppButton(); + // wait slide effect + await navigation.sleep(500); await applicationCreatePanel.clickCancelButton(); await UiTestUtilities.log('Test passed'); } catch (e) {