diff --git a/tests/e2e/configs/inversify.config.ts b/tests/e2e/configs/inversify.config.ts index 983a0f638d95..7e55a45fd53e 100644 --- a/tests/e2e/configs/inversify.config.ts +++ b/tests/e2e/configs/inversify.config.ts @@ -39,6 +39,9 @@ import { ProjectAndFileTests } from '../tests-library/ProjectAndFileTests'; import { LoginTests } from '../tests-library/LoginTests'; import { RedHatLoginPage } from '../pageobjects/login/RedHatLoginPage'; import { OcpRedHatLoginPage } from '../pageobjects/login/OcpRedHatLoginPage'; +import { OcpMainPage } from '../pageobjects/openshift/OcpMainPage'; +import { OcpImportFromGitPage } from '../pageobjects/openshift/OcpImportFromGitPage'; +import { OcpApplicationPage } from '../pageobjects/openshift/OcpApplicationPage'; const e2eContainer: Container = new Container({defaultScope: 'Transient'}); @@ -53,6 +56,12 @@ e2eContainer.bind(CLASSES.Workspaces).to(Workspaces); e2eContainer.bind(CLASSES.WorkspaceDetails).to(WorkspaceDetails); e2eContainer.bind(CLASSES.ScreenCatcher).to(ScreenCatcher); e2eContainer.bind(CLASSES.OcpLoginPage).to(OcpLoginPage); + +e2eContainer.bind(CLASSES.OcpMainPage).to(OcpMainPage); +e2eContainer.bind(CLASSES.OcpImportFromGitPage).to(OcpImportFromGitPage); +e2eContainer.bind(CLASSES.OcpApplicationPage).to(OcpApplicationPage); + + e2eContainer.bind(CLASSES.CheLoginPage).to(CheLoginPage); e2eContainer.bind(CLASSES.CheApiRequestHandler).to(CheApiRequestHandler); e2eContainer.bind(CLASSES.CreateWorkspace).to(CreateWorkspace); @@ -61,13 +70,10 @@ e2eContainer.bind(CLASSES.LoginTests).to(LoginTests); e2eContainer.bind(CLASSES.Sanitizer).to(Sanitizer); e2eContainer.bind(CLASSES.ApiUrlResolver).to(ApiUrlResolver); e2eContainer.bind(CLASSES.WorkspaceHandlingTests).to(WorkspaceHandlingTests); +e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); TestConstants.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH ? e2eContainer.bind(TYPES.CheLogin).to(RegularUserOcpCheLoginPage) : e2eContainer.bind(TYPES.CheLogin).to(OcpRedHatLoginPage); -if (TestConstants.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE === 'DevSandbox') { - e2eContainer.bind(CLASSES.RedHatLoginPage).to(RedHatLoginPage); -} - export { e2eContainer }; diff --git a/tests/e2e/configs/inversify.types.ts b/tests/e2e/configs/inversify.types.ts index 511f9abcdba3..34cb189644c1 100644 --- a/tests/e2e/configs/inversify.types.ts +++ b/tests/e2e/configs/inversify.types.ts @@ -36,6 +36,9 @@ const CLASSES: any = { WorkspaceHandlingTests: 'WorkspaceHandlingTests', RedHatLoginPage: 'RedHatLoginPage', OcpRedHatLoginPage: 'OcpRedHatLoginPage', + OcpApplicationPage: 'OcpApplicationPage', + OcpMainPage: 'OcpMainPage', + OcpImportFromGitPage: 'OcpImportFromGitPage' }; export { TYPES, CLASSES }; diff --git a/tests/e2e/constants/TestConstants.ts b/tests/e2e/constants/TestConstants.ts index 725be8e6772c..208b7ae30d9c 100644 --- a/tests/e2e/constants/TestConstants.ts +++ b/tests/e2e/constants/TestConstants.ts @@ -34,6 +34,10 @@ export const TestConstants: any = { */ TS_SELENIUM_BASE_URL: getBaseUrl(), + TS_SELENIUM_OPENSHIFT_CONSOLE_URL(): string { + return process.env.TS_SELENIUM_OPENSHIFT_CONSOLE_URL || TestConstants.TS_SELENIUM_BASE_URL.replace('devspaces', 'console-openshift-console'); + }, + /** * Run browser in "Headless" (hidden) mode, "false" by default. */ diff --git a/tests/e2e/index.ts b/tests/e2e/index.ts index 1a12bf418b05..ed41f8a793bf 100644 --- a/tests/e2e/index.ts +++ b/tests/e2e/index.ts @@ -33,7 +33,10 @@ export * from './pageobjects/login/OcpUserLoginPage'; export * from './pageobjects/login/RedHatLoginPage'; export * from './pageobjects/login/RegularUserOcpCheLoginPage'; export * from './pageobjects/openshift/CheLoginPage'; +export * from './pageobjects/openshift/OcpApplicationPage'; +export * from './pageobjects/openshift/OcpImportFromGitPage'; export * from './pageobjects/openshift/OcpLoginPage'; +export * from './pageobjects/openshift/OcpMainPage'; export * from './tests-library/LoginTests'; export * from './tests-library/ProjectAndFileTests'; export * from './tests-library/WorkspaceHandlingTests'; diff --git a/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts new file mode 100644 index 000000000000..1b9cb2260ea3 --- /dev/null +++ b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts @@ -0,0 +1,39 @@ +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { inject, injectable } from 'inversify'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { Logger } from '../../utils/Logger'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; + +@injectable() +export class OcpApplicationPage { + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, + @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil) { + } + + async waitApplicationIcon(): Promise { + Logger.debug(`${this.constructor.name}.${this.waitApplicationIcon.name}`); + + await this.driverHelper.waitPresence(By.xpath('//*[@data-test-id="base-node-handler"]'), TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async waitAndOpenEditSourceCodeIcon(): Promise { + Logger.debug(`${this.constructor.name}.${this.waitAndOpenEditSourceCodeIcon.name}`); + const parentGUID: string = await this.browserTabsUtil.getCurrentWindowHandle(); + await this.driverHelper.waitAndClick(By.xpath('//*[@aria-label="Edit source code"]')); + await this.browserTabsUtil.waitAndSwitchToAnotherWindow(parentGUID, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } +} diff --git a/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts new file mode 100644 index 000000000000..a4e10167ec20 --- /dev/null +++ b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts @@ -0,0 +1,82 @@ +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { inject, injectable } from 'inversify'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { Logger } from '../../utils/Logger'; +import { OcpApplicationPage } from './OcpApplicationPage'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { e2eContainer } from '../../configs/inversify.config'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; + +@injectable() +export class OcpImportFromGitPage { + private readonly TIMEOUT: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM * 3; + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, + @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil) { + } + + async enterGitRepoUrl(gitRepoUrl: string): Promise { + Logger.debug(`${this.constructor.name}.${this.enterGitRepoUrl.name} "${gitRepoUrl}"`); + + await this.driverHelper.enterValue(By.id('form-input-git-url-field'), gitRepoUrl, this.TIMEOUT); + } + + async clickOnAdvancedOptionsButton(): Promise { + Logger.debug(`${this.constructor.name}.${this.clickOnAdvancedOptionsButton.name}`); + + if (!(await this.driverHelper.isVisible(By.xpath('//*[text()="Hide advanced Git options"]')))) { + await this.driverHelper.waitAndClick(By.xpath('//*[text()="Show advanced Git options"]//ancestor::button'), this.TIMEOUT); + } + } + + async enterGitReference(gitReference: string): Promise { + Logger.debug(`${this.constructor.name}.${this.enterGitReference.name} "${gitReference}"`); + + await this.driverHelper.enterValue(By.id('form-input-git-ref-field'), gitReference, this.TIMEOUT); + } + + async selectBuilderImageImportStrategy(): Promise { + Logger.debug(`${this.constructor.name}.${this.selectBuilderImageImportStrategy.name}`); + + await this.driverHelper.waitPresence(By.xpath('//*[text()="Import is not possible."]'), this.TIMEOUT); + await this.driverHelper.waitAndClick(By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'), this.TIMEOUT); + await this.driverHelper.waitAndClick(By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'), this.TIMEOUT); + } + + async addLabel(label: string): Promise { + Logger.debug(`${this.constructor.name}.${this.addLabel.name} "${label}"`); + + await this.driverHelper.waitAndClick(By.xpath('//button[text()="Labels"]'), this.TIMEOUT); + await this.driverHelper.enterValue(By.id('form-selector-labels-field'), label, this.TIMEOUT); + } + + async submitConfiguration(): Promise { + Logger.debug(`${this.constructor.name}.${this.submitConfiguration.name}`); + + await this.driverHelper.waitAndClick(By.xpath('//*[@data-test-id="submit-button"]'), this.TIMEOUT); + return e2eContainer.get(CLASSES.OcpApplicationPage); + } + + async fitAndSubmitConfiguration(gitRepoUrl: string, gitReference: string, label: string): Promise { + Logger.debug(`${this.constructor.name}.${this.fitAndSubmitConfiguration.name}`); + + await this.enterGitRepoUrl(gitRepoUrl); + await this.clickOnAdvancedOptionsButton(); + await this.enterGitReference(gitReference); + await this.selectBuilderImageImportStrategy(); + await this.addLabel(label); + return await this.submitConfiguration(); + } +} diff --git a/tests/e2e/pageobjects/openshift/OcpLoginPage.ts b/tests/e2e/pageobjects/openshift/OcpLoginPage.ts index 98e2de57064a..8be2a7e95b3a 100644 --- a/tests/e2e/pageobjects/openshift/OcpLoginPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpLoginPage.ts @@ -80,13 +80,13 @@ export class OcpLoginPage { async clickOnLoginButton(): Promise { Logger.debug('OcpLoginPage.clickOnLoginButton'); - const loginButtonlocator: By = By.css('button[type=submit]'); - await this.driverHelper.waitAndClick(loginButtonlocator); + const loginButtonLocator: By = By.css('button[type=submit]'); + await this.driverHelper.waitAndClick(loginButtonLocator); } async waitDisappearanceOpenShiftLoginWelcomePage(): Promise { Logger.debug('OcpLoginPage.waitDisappearanceOpenShiftLoginWelcomePage'); - await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH)); + await this.driverHelper.waitDisappearance(By.xpath(OcpLoginPage.LOGIN_PAGE_OPENSHIFT_XPATH), TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS * 10); } } diff --git a/tests/e2e/pageobjects/openshift/OcpMainPage.ts b/tests/e2e/pageobjects/openshift/OcpMainPage.ts new file mode 100644 index 000000000000..10eee6c3956e --- /dev/null +++ b/tests/e2e/pageobjects/openshift/OcpMainPage.ts @@ -0,0 +1,89 @@ +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ +import 'reflect-metadata'; +import { inject, injectable } from 'inversify'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CLASSES } from '../../configs/inversify.types'; +import { By } from 'selenium-webdriver'; +import { Logger } from '../../utils/Logger'; +import { TimeoutConstants } from '../../constants/TimeoutConstants'; +import { OcpImportFromGitPage } from './OcpImportFromGitPage'; +import { BrowserTabsUtil } from '../../utils/BrowserTabsUtil'; +import { e2eContainer } from '../../configs/inversify.config'; + +@injectable() +export class OcpMainPage { + + private static readonly MAIN_PAGE_HEADER_LOCATOR: By = By.id('page-main-header'); + private static readonly SELECT_ROLE_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="perspective-switcher-toggle"]'); + private static readonly ADD_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="+Add-header"]'); + private static readonly IMPORT_FROM_GIT_ITEM_LOCATOR: By = By.xpath('//*[@data-test="item import-from-git"]'); + private static readonly SELECT_PROJECT_DROPDOWN_LOCATOR: By = By.xpath('//div[@class="co-namespace-dropdown"]//button'); + private static readonly PROJECT_FILTER_INPUT_LOCATOR: By = By.xpath('//*[@data-test="dropdown-text-filter"]'); + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper, + @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil) { } + + async waitOpenMainPage(): Promise { + Logger.debug(`${this.constructor.name}.${this.waitOpenMainPage.name}`); + + await this.driverHelper.waitVisibility(OcpMainPage.MAIN_PAGE_HEADER_LOCATOR, TimeoutConstants.TS_SELENIUM_LOAD_PAGE_TIMEOUT); + } + + async clickOnSelectRoleButton(): Promise { + Logger.debug(`${this.constructor.name}.${this.clickOnSelectRoleButton.name}`); + + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_ROLE_BUTTON_LOCATOR); + } + + async clickAddToProjectButton(): Promise { + Logger.debug(`${this.constructor.name}.${this.clickAddToProjectButton.name}`); + + await this.driverHelper.waitAndClick(OcpMainPage.ADD_BUTTON_LOCATOR); + } + + async selectDeveloperRole(): Promise { + Logger.debug(`${this.constructor.name}.${this.selectDeveloperRole.name}`); + + await this.driverHelper.waitAndClick(this.getRoleLocator('Developer')); + } + + async selectImportFromGitMethod(): Promise { + Logger.debug(`${this.constructor.name}.${this.selectImportFromGitMethod.name}`); + + await this.driverHelper.waitAndClick(OcpMainPage.IMPORT_FROM_GIT_ITEM_LOCATOR); + return e2eContainer.get(CLASSES.OcpImportFromGitPage); + } + + async openImportFromGitPage(): Promise { + await this.waitOpenMainPage(); + await this.clickOnSelectRoleButton(); + await this.selectDeveloperRole(); + await this.clickAddToProjectButton(); + return await this.selectImportFromGitMethod(); + } + + async selectProject(projectName: string): Promise { + Logger.debug(`${this.constructor.name}.${this.selectProject.name}`); + + await this.driverHelper.waitAndClick(OcpMainPage.SELECT_PROJECT_DROPDOWN_LOCATOR); + await this.driverHelper.enterValue(OcpMainPage.PROJECT_FILTER_INPUT_LOCATOR, projectName); + await this.driverHelper.waitAndClick(this.getProjectDropdownItemLocator(projectName)); + } + + private getRoleLocator(role: string): By { + return By.xpath(`//a//*[text()="${role}"]`); + } + + private getProjectDropdownItemLocator(projectName: string): By { + return By.xpath(`//button//*[text()="${projectName}"]`); + } +} diff --git a/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts new file mode 100644 index 000000000000..fc361ce0e563 --- /dev/null +++ b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts @@ -0,0 +1,102 @@ +/********************************************************************* + * Copyright (c) 2019-2023 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + **********************************************************************/ + +import { + SideBarView, + ViewItem, + ViewSection +} from 'monaco-page-objects'; +import { registerRunningWorkspace } from '../MochaHooks'; +import { LoginTests } from '../../tests-library/LoginTests'; +import { e2eContainer } from '../../configs/inversify.config'; +import { CLASSES } from '../../configs/inversify.types'; +import { WorkspaceHandlingTests } from '../../tests-library/WorkspaceHandlingTests'; +import { ProjectAndFileTests } from '../../tests-library/ProjectAndFileTests'; +import { Logger } from '../../utils/Logger'; +import { expect } from 'chai'; +import { TestConstants } from '../../constants/TestConstants'; +import { OcpMainPage } from '../../pageobjects/openshift/OcpMainPage'; +import { OcpImportFromGitPage } from '../../pageobjects/openshift/OcpImportFromGitPage'; +import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor'; +import { GitUtil } from '../../utils/vsc/GitUtil'; +import { OcpApplicationPage } from '../../pageobjects/openshift/OcpApplicationPage'; +import { DriverHelper } from '../../utils/DriverHelper'; + +const projectAndFileTests: ProjectAndFileTests = e2eContainer.get(CLASSES.ProjectAndFileTests); +const loginTests: LoginTests = e2eContainer.get(CLASSES.LoginTests); +const workspaceHandlingTests: WorkspaceHandlingTests = e2eContainer.get(CLASSES.WorkspaceHandlingTests); +const ocpMainPage: OcpMainPage = e2eContainer.get(CLASSES.OcpMainPage); +const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); +let ocpImportPage: OcpImportFromGitPage; +let ocpApplicationPage: OcpApplicationPage; +const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(); + +// test specific data +const gitImportRepo: string = 'https://github.com/musienko-maxim/summit-lab-spring-music'; +const gitImportReference: string = 'pipeline'; +const projectLabel: string = 'app.openshift.io/runtime=spring'; +const projectName: string = 'devconsole-integration-test'; + +suite(`DevConsole Integration`, async function (): Promise { + suiteSetup('Create new empty project using ocp', async function (): Promise { + kubernetesCommandLineToolsExecutor.loginToOcp(); + try { + kubernetesCommandLineToolsExecutor.deleteProject(projectName); + } catch (e) { + Logger.debug(`Project "${projectName}" does not exist`); + } + kubernetesCommandLineToolsExecutor.createProject(projectName); + }); + + loginTests.loginIntoOcpConsole(); + + test('Select test project on DevConsole', async function (): Promise { + await ocpMainPage.selectProject(projectName); + }); + + test('Open import from git project page as Developer', async function (): Promise { + ocpImportPage = await ocpMainPage.openImportFromGitPage(); + }); + + test('Fill and submit import data', async function (): Promise { + this.retries(5); + await driverHelper.refreshPage(); + ocpApplicationPage = await ocpImportPage.fitAndSubmitConfiguration(gitImportRepo, gitImportReference, projectLabel); + }); + + test('Wait until application creates', async function (): Promise { + await ocpApplicationPage.waitApplicationIcon(); + }); + + test('Check if application has worked link "Open Source Code"', async function (): Promise { + await ocpApplicationPage.waitAndOpenEditSourceCodeIcon(); + }); + + loginTests.loginIntoChe(); + + workspaceHandlingTests.obtainWorkspaceNameFromStartingPage(); + + test('Registering the running workspace', async function (): Promise { + registerRunningWorkspace(WorkspaceHandlingTests.getWorkspaceName()); + }); + + test('Check if application source code opens in workspace', async function (): Promise { + await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); + }); + + test('Check if project and files imported', async function (): Promise { + const applicationSourceProjectName: string = GitUtil.getProjectNameFromGitUrl(gitImportRepo); + const projectSection: ViewSection = await new SideBarView().getContent().getSection(applicationSourceProjectName as unknown as string); + const isFileImported: ViewItem | undefined = await projectSection.findItem(TestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); + expect(isFileImported).not.eqls(undefined); + }); + + loginTests.logoutFromChe(); +}); diff --git a/tests/e2e/tests-library/LoginTests.ts b/tests/e2e/tests-library/LoginTests.ts index f28acda2a3de..2ae8cc55373b 100644 --- a/tests/e2e/tests-library/LoginTests.ts +++ b/tests/e2e/tests-library/LoginTests.ts @@ -12,27 +12,35 @@ import { CLASSES, TYPES } from '../configs/inversify.types'; import { ICheLoginPage } from '../pageobjects/login/ICheLoginPage'; import { TestConstants } from '../constants/TestConstants'; import { BrowserTabsUtil } from '../utils/BrowserTabsUtil'; -import { Logger } from '../utils/Logger'; import { inject, injectable } from 'inversify'; import { Dashboard } from '../pageobjects/dashboard/Dashboard'; +import { IOcpLoginPage } from '../pageobjects/login/IOcpLoginPage'; @injectable() export class LoginTests { constructor( @inject(CLASSES.BrowserTabsUtil) private readonly browserTabsUtil: BrowserTabsUtil, - @inject(TYPES.CheLogin) private readonly loginPage: ICheLoginPage, + @inject(TYPES.CheLogin) private readonly productLoginPage: ICheLoginPage, + @inject(TYPES.OcpLogin) private readonly ocpLoginPage: IOcpLoginPage, @inject(CLASSES.Dashboard) private readonly dashboard: Dashboard) { } public loginIntoChe(): void { test('Login', async () => { - await this.browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_BASE_URL); - await this.loginPage.login(); - if (TestConstants.TS_SELENIUM_LAUNCH_FULLSCREEN) { - Logger.debug(`TS_SELENIUM_LAUNCH_FULLSCREEN is set to true, maximizing window.`); - await this.browserTabsUtil.maximize(); - await this.dashboard.waitStartingPageLoaderDisappearance(); + if (!(await this.browserTabsUtil.getCurrentUrl()).includes(TestConstants.TS_SELENIUM_BASE_URL)) { + await this.browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_BASE_URL); } + await this.productLoginPage.login(); + await this.browserTabsUtil.maximize(); + await this.dashboard.waitStartingPageLoaderDisappearance(); + }); + } + + public loginIntoOcpConsole(): void { + test('Login into ocp console', async () => { + await this.browserTabsUtil.navigateTo(TestConstants.TS_SELENIUM_OPENSHIFT_CONSOLE_URL()); + await this.ocpLoginPage.login(); + await this.browserTabsUtil.maximize(); }); } diff --git a/tests/e2e/utils/BrowserTabsUtil.ts b/tests/e2e/utils/BrowserTabsUtil.ts index efb0f7256d84..32bfc2db6dcb 100644 --- a/tests/e2e/utils/BrowserTabsUtil.ts +++ b/tests/e2e/utils/BrowserTabsUtil.ts @@ -13,6 +13,7 @@ import { CLASSES } from '../configs/inversify.types'; import { DriverHelper } from './DriverHelper'; import { Logger } from './Logger'; import { TimeoutConstants } from '../constants/TimeoutConstants'; +import { TestConstants } from '../constants/TestConstants'; @injectable() export class BrowserTabsUtil { @@ -91,8 +92,9 @@ export class BrowserTabsUtil { public async maximize(): Promise { Logger.trace(`BrowserTabsUtil.maximize`); - - await this.driverHelper.getDriver().manage().window().maximize(); + if (TestConstants.TS_SELENIUM_LAUNCH_FULLSCREEN) { + Logger.debug(`TS_SELENIUM_LAUNCH_FULLSCREEN is set to true, maximizing window.`); + await this.driverHelper.getDriver().manage().window().maximize(); + } } - } diff --git a/tests/e2e/utils/DriverHelper.ts b/tests/e2e/utils/DriverHelper.ts index 063eae7baa62..251850c07e25 100644 --- a/tests/e2e/utils/DriverHelper.ts +++ b/tests/e2e/utils/DriverHelper.ts @@ -48,6 +48,12 @@ export class DriverHelper { await this.driver.sleep(milliseconds); } + public async refreshPage(): Promise { + Logger.trace(`DriverHelper.refreshPage`); + + await this.driver.navigate().refresh(); + } + public async waitVisibilityBoolean(locator: By, attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING): Promise { @@ -253,7 +259,7 @@ export class DriverHelper { for (let i: number = 0; i < attempts; i++) { let element: WebElement; try { - element = await this.waitVisibility(elementLocator, polling); + element = await this.waitPresence(elementLocator, polling); } catch (err) { if (i >= attempts - 1) { Logger.error(`DriverHelper.waitAndClick - failed with exception, out of attempts - ${err}`); @@ -273,12 +279,23 @@ export class DriverHelper { await element.click(); return; } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - Logger.debug(`DriverHelper.waitAndClik - ${elementLocator} - StaleElementReferenceError - ${err}`); + if (err instanceof error.StaleElementReferenceError || (err instanceof error.ElementClickInterceptedError && i !== attempts - 1)) { + Logger.debug(`DriverHelper.waitAndClick - ${elementLocator} - StaleElementReferenceError - ${err}`); await this.wait(polling); continue; } + if (err instanceof error.ElementClickInterceptedError && i === attempts - 1) { + Logger.trace(`DriverHelper.waitAndClick - Element is not clickable, try to perform pointer click`); + await this.getAction() + .move({ + origin: await this.waitPresence(elementLocator, polling) + }) + .click() + .perform(); + return; + } + Logger.error(`DriverHelper.waitAndClick - failed with an unexpected exception - ${err}`); throw err; } diff --git a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts index 06025c4fab30..fcb32ecb116f 100644 --- a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts +++ b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts @@ -2,6 +2,7 @@ import { echo, exec, ShellString } from 'shelljs'; import { KubernetesCommandLineTool, TestConstants } from '../constants/TestConstants'; import { Logger } from './Logger'; import { ShellExecutor } from './ShellExecutor'; +import { TimeoutConstants } from '../constants/TimeoutConstants'; export class KubernetesCommandLineToolsExecutor extends ShellExecutor { private static container: string; @@ -89,6 +90,27 @@ export class KubernetesCommandLineToolsExecutor extends ShellExecutor { this.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} create namespace ${this.namespace}`); } + createProject(projectName: string, timeout: number = TimeoutConstants.TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT * 2): void { + Logger.debug(`${this.getLoggingName(this.createProject.name)}: Create new project "${projectName}".`); + const polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING; + const attempts: number = Math.ceil(timeout / polling); + let response: ShellString; + for (let i: number = 0; i < attempts; i++) { + response = this.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} new-project ${projectName} -n ${this.namespace}`); + if ((response.stderr + response.stdout).includes('already exist')) { + Logger.trace(`${this.getLoggingName(this.createProject.name)} - Project already exist #${(i + 1)}, retrying with ${polling}ms timeout`); + exec(`sleep ${polling / 1000}s`); + } else { + break; + } + } + } + + deleteProject(projectName: string): void { + Logger.debug(`${this.getLoggingName(this.deleteProject.name)}: Delete "${projectName}".`); + this.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} delete project ${projectName} -n ${this.namespace} && sleep 5s`); + } + private getLoggingName(methodName: string): string { return `${this.constructor.name}.${methodName} - ${(this.KUBERNETES_COMMAND_LINE_TOOL)}`; } @@ -110,7 +132,7 @@ export class KubernetesCommandLineToolsExecutor extends ShellExecutor { export namespace KubernetesCommandLineToolsExecutor { export class ContainerTerminal extends KubernetesCommandLineToolsExecutor { constructor(cluster: KubernetesCommandLineToolsExecutor) { - super(cluster.getWorkspaceName, cluster.getNamespace); + super(cluster.getWorkspaceName, cluster.getNamespace); } ls(path: string = ''): ShellString {