diff --git a/tests/e2e/configs/inversify.config.ts b/tests/e2e/configs/inversify.config.ts index 983a0f638d9..7e55a45fd53 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 511f9abcdba..34cb189644c 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/index.ts b/tests/e2e/index.ts index 1a12bf418b0..ed41f8a793b 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 00000000000..e4aeec1fb25 --- /dev/null +++ b/tests/e2e/pageobjects/openshift/OcpApplicationPage.ts @@ -0,0 +1,42 @@ +/********************************************************************* + * 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 { + + private static readonly APPLICATION_ICON_LOCATOR: By = By.xpath('//*[@data-test-id="base-node-handler"]'); + private static readonly EDIT_SOURCE_CODE_ICON_LOCATOR: By = By.xpath('//*[@aria-label="Edit source code"]'); + + 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(OcpApplicationPage.APPLICATION_ICON_LOCATOR, 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(OcpApplicationPage.EDIT_SOURCE_CODE_ICON_LOCATOR); + 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 00000000000..4e9ea3abb38 --- /dev/null +++ b/tests/e2e/pageobjects/openshift/OcpImportFromGitPage.ts @@ -0,0 +1,87 @@ +/********************************************************************* + * 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 { e2eContainer } from '../../configs/inversify.config'; + +@injectable() +export class OcpImportFromGitPage { + + private static readonly GIT_URL_INPUT_LOCATOR: By = By.id('form-input-git-url-field'); + private static readonly SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR: By = By.xpath('//*[text()="Show advanced Git options"]//ancestor::button'); + private static readonly HIDE_ADVANCED_GIT_OPTIONS_LOCATOR: By = By.xpath('//*[text()="Hide advanced Git options"]'); + private static readonly GIT_REFERENCE_INPUT_LOCATOR: By = By.id('form-input-git-ref-field'); + private static readonly EDIT_IMPORT_STRATEGY_LINK_LOCATOR: By = By.xpath('//*[text()="Edit Import Strategy"]//ancestor::button'); + private static readonly BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR: By = By.xpath('//*[text()="Builder Image"]//parent::div//parent::div'); + private static readonly ADD_LABEL_LINK_LOCATOR: By = By.xpath('//button[text()="Labels"]'); + private static readonly ADD_LABEL_INPUT_LOCATOR: By = By.id('form-selector-labels-field'); + private static readonly SUBMIT_BUTTON_LOCATOR: By = By.xpath('//*[@data-test-id="submit-button"]'); + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { + } + + async enterGitRepoUrl(gitRepoUrl: string): Promise { + Logger.debug(`${this.constructor.name}.${this.enterGitRepoUrl.name} "${gitRepoUrl}"`); + + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_URL_INPUT_LOCATOR, gitRepoUrl); + } + + async clickOnAdvancedOptionsButton(): Promise { + Logger.debug(`${this.constructor.name}.${this.clickOnAdvancedOptionsButton.name}`); + + if (!(await this.driverHelper.isVisible(OcpImportFromGitPage.HIDE_ADVANCED_GIT_OPTIONS_LOCATOR))) { + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SHOW_ADVANCED_GIT_OPTIONS_LINK_LOCATOR); + } + } + + async enterGitReference(gitReference: string): Promise { + Logger.debug(`${this.constructor.name}.${this.enterGitReference.name} "${gitReference}"`); + + await this.driverHelper.enterValue(OcpImportFromGitPage.GIT_REFERENCE_INPUT_LOCATOR, gitReference); + } + + async selectBuilderImageImportStrategy(): Promise { + Logger.debug(`${this.constructor.name}.${this.selectBuilderImageImportStrategy.name}`); + + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.EDIT_IMPORT_STRATEGY_LINK_LOCATOR); + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.BUILDER_IMAGE_STRATEGY_ITEM_LOCATOR); + } + + async addLabel(label: string): Promise { + Logger.debug(`${this.constructor.name}.${this.addLabel.name} "${label}"`); + + await this.driverHelper.scrollToAndClick(OcpImportFromGitPage.ADD_LABEL_LINK_LOCATOR); + await this.driverHelper.scrollToAndEnterValue(OcpImportFromGitPage.ADD_LABEL_INPUT_LOCATOR, label); + } + + async submitConfiguration(): Promise { + Logger.debug(`${this.constructor.name}.${this.submitConfiguration.name}`); + + await this.driverHelper.waitAndClick(OcpImportFromGitPage.SUBMIT_BUTTON_LOCATOR); + 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 98e2de57064..eb44d012388 100644 --- a/tests/e2e/pageobjects/openshift/OcpLoginPage.ts +++ b/tests/e2e/pageobjects/openshift/OcpLoginPage.ts @@ -34,7 +34,7 @@ export class OcpLoginPage { Logger.debug('OcpLoginPage.clickOnLoginProviderTitle'); const loginProviderTitleLocator: By = By.xpath(`//a[text()=\'${TestConstants.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE}\']`); - await this.driverHelper.waitAndClick(loginProviderTitleLocator); + await this.driverHelper.waitAndClick(loginProviderTitleLocator, TimeoutConstants.TS_SELENIUM_WAIT_FOR_URL); } async isIdentityProviderLinkVisible(): Promise { @@ -80,8 +80,8 @@ 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 { diff --git a/tests/e2e/pageobjects/openshift/OcpMainPage.ts b/tests/e2e/pageobjects/openshift/OcpMainPage.ts new file mode 100644 index 00000000000..3017ae7c5c1 --- /dev/null +++ b/tests/e2e/pageobjects/openshift/OcpMainPage.ts @@ -0,0 +1,87 @@ +/********************************************************************* + * 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 { 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"]'); + + private static getRoleLocator(role: string): By { + return By.xpath(`//a//*[text()="${role}"]`); + } + + private static getProjectDropdownItemLocator(projectName: string): By { + return By.xpath(`//button//*[text()="${projectName}"]`); + } + + constructor( + @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + 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(OcpMainPage.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(OcpMainPage.getProjectDropdownItemLocator(projectName)); + } +} diff --git a/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts b/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts index 6bd00d58392..8cb998ff733 100644 --- a/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts +++ b/tests/e2e/specs/dashboard-samples/RecomendedExtentions.spec.ts @@ -109,7 +109,7 @@ suite(`Check if recommended extensions installed for ${samples}`, async function test(`Let extensions complete installation`, async function (): Promise { Logger.info(`Time for extensions installation TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT=${TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT}`); await driverHelper.wait(TimeoutConstants.TS_COMMON_PLUGIN_TEST_TIMEOUT); - browserTabsUtil.refreshPage(); + await browserTabsUtil.refreshPage(); await projectAndFileTests.waitWorkspaceReadinessForCheCodeEditor(); }); 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 00000000000..b13887e832d --- /dev/null +++ b/tests/e2e/specs/devconsole-intergration/DevConsoleIntegration.spec.ts @@ -0,0 +1,97 @@ +/********************************************************************* + * 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 { 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'; + +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); +let ocpImportPage: OcpImportFromGitPage; +let ocpApplicationPage: OcpApplicationPage; +const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(); + +// works only with no-admin user +suite(`DevConsole Integration`, async function (): Promise { + // test specific data + const gitImportRepo: string = 'https://github.com/crw-qe/summit-lab-spring-music.git'; + const gitImportReference: string = 'pipeline'; + const projectLabel: string = 'app.openshift.io/runtime=spring'; + const projectName: string = 'devconsole-integration-test'; + + suiteSetup('Create new empty project using ocp', async function (): Promise { + kubernetesCommandLineToolsExecutor.loginToOcp(); + 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 { + 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); + const isFileImported: ViewItem | undefined = await projectSection.findItem(TestConstants.TS_SELENIUM_PROJECT_ROOT_FILE_NAME); + expect(isFileImported).not.eqls(undefined); + }); + + loginTests.logoutFromChe(); + + suiteTeardown('Delete project using ocp', async function (): Promise { + kubernetesCommandLineToolsExecutor.deleteProject(projectName); + }); +}); diff --git a/tests/e2e/specs/factory/Factory.spec.ts b/tests/e2e/specs/factory/Factory.spec.ts index e6c48788263..ec07d15b97e 100644 --- a/tests/e2e/specs/factory/Factory.spec.ts +++ b/tests/e2e/specs/factory/Factory.spec.ts @@ -89,7 +89,7 @@ suite(`Create a workspace via launching a factory from the ${TestConstants.TS_SE test('Check if a project folder has been created', async function (): Promise { Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); - projectSection = await new SideBarView().getContent().getSection(testRepoProjectName as unknown as string); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); }); test('Check if the project files were imported', async function (): Promise { diff --git a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts index 5cfd27839c6..bb0acece638 100644 --- a/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts +++ b/tests/e2e/specs/factory/NoSetupRepoFactory.spec.ts @@ -115,7 +115,7 @@ suite(`Create a workspace via launching a factory from the ${TestConstants.TS_SE test('Check if a project folder has been created', async function (): Promise { Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); - projectSection = await new SideBarView().getContent().getSection(testRepoProjectName as unknown as string); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); }); test('Accept the project as a trusted one', async function (): Promise { diff --git a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts index acf81fe09c3..10338233890 100644 --- a/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts +++ b/tests/e2e/specs/factory/RefusedOAuthFactory.spec.ts @@ -98,7 +98,7 @@ suite(`Create a workspace via launching a factory from the ${TestConstants.TS_SE test('Check if a project folder has been created', async function (): Promise { Logger.debug(`new SideBarView().getContent().getSection: get ${testRepoProjectName}`); - projectSection = await new SideBarView().getContent().getSection(testRepoProjectName as unknown as string); + projectSection = await new SideBarView().getContent().getSection(testRepoProjectName); }); test('Accept the project as a trusted one', async function (): Promise { diff --git a/tests/e2e/tests-library/LoginTests.ts b/tests/e2e/tests-library/LoginTests.ts index f28acda2a3d..c628586de38 100644 --- a/tests/e2e/tests-library/LoginTests.ts +++ b/tests/e2e/tests-library/LoginTests.ts @@ -12,27 +12,36 @@ 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 () => { + const openshiftConsoleUrl: string = TestConstants.TS_SELENIUM_BASE_URL.replace('devspaces', 'console-openshift-console'); + await this.browserTabsUtil.navigateTo(openshiftConsoleUrl); + await this.ocpLoginPage.login(); + await this.browserTabsUtil.maximize(); }); } diff --git a/tests/e2e/utils/BrowserTabsUtil.ts b/tests/e2e/utils/BrowserTabsUtil.ts index efb0f7256d8..32bfc2db6dc 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 063eae7baa6..dd2256d3b7a 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 { @@ -273,12 +279,27 @@ export class DriverHelper { await element.click(); return; } catch (err) { - if (err instanceof error.StaleElementReferenceError) { - Logger.debug(`DriverHelper.waitAndClik - ${elementLocator} - StaleElementReferenceError - ${err}`); + function isElementClickInterceptedOnLastAttempt(err: Error, i: number): boolean { + return err instanceof error.ElementClickInterceptedError && i === attempts - 1; + } + + if (err instanceof error.StaleElementReferenceError || err instanceof error.ElementClickInterceptedError) { + Logger.debug(`DriverHelper.waitAndClick - ${elementLocator} - ${err}`); await this.wait(polling); continue; } + if (isElementClickInterceptedOnLastAttempt(err, i)) { + Logger.debug(`DriverHelper.waitAndClick - Element is not clickable, try to perform pointer click`); + await this.getAction() + .move({ + origin: await this.waitPresence(elementLocator) + }) + .click() + .perform(); + return; + } + Logger.error(`DriverHelper.waitAndClick - failed with an unexpected exception - ${err}`); throw err; } @@ -658,7 +679,8 @@ export class DriverHelper { } try { - await this.getAction().move({origin: element}).perform(); + await this.getDriver() + .executeScript('arguments[0].scrollIntoView(true);', element); return; } catch (err) { if (err instanceof error.StaleElementReferenceError) { @@ -674,7 +696,17 @@ export class DriverHelper { throw new error.TimeoutError(`Exceeded maximum mouse move attempts, for the '${elementLocator}' element`); } - getDriver(): ThenableWebDriver { + public async scrollToAndClick(elementLocator: By, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + await this.scrollTo(elementLocator, timeout); + await this.waitAndClick(elementLocator, timeout); + } + + public async scrollToAndEnterValue(elementLocator: By, value: string, timeout: number = TimeoutConstants.TS_SELENIUM_CLICK_ON_VISIBLE_ITEM): Promise { + await this.scrollTo(elementLocator, timeout); + await this.enterValue(elementLocator, value, timeout); + } + + getDriver(): ThenableWebDriver { Logger.trace('DriverHelper.getDriver'); return this.driver; diff --git a/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts b/tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts index 06025c4fab3..edbbb6e807c 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; @@ -27,11 +28,14 @@ export class KubernetesCommandLineToolsExecutor extends ShellExecutor { // login to Openshift cluster with username and password loginToOcp(): void { if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.OC) { - Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: Login to the "OC" client`); + Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: Login to the "OC" client.`); const url: string = this.getServerUrl(); - Logger.debug(url, TestConstants.TS_SELENIUM_OCP_USERNAME); - exec(`sleep 5 - oc login --server=${url} -u=${TestConstants.TS_SELENIUM_OCP_USERNAME} -p=${TestConstants.TS_SELENIUM_OCP_PASSWORD} --insecure-skip-tls-verify`); + if (this.isUserLoggedIn()) { + Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: User already logged`); + } else { + Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: Login ${url}, ${TestConstants.TS_SELENIUM_OCP_USERNAME}`); + exec(`oc login --server=${url} -u=${TestConstants.TS_SELENIUM_OCP_USERNAME} -p=${TestConstants.TS_SELENIUM_OCP_PASSWORD} --insecure-skip-tls-verify`); + } } else { Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: doesn't support login command`); } @@ -54,6 +58,7 @@ export class KubernetesCommandLineToolsExecutor extends ShellExecutor { Logger.debug(`${this.getLoggingName(this.deleteDevWorkspace.name)}: Delete '${this.workspaceName}' workspace`); this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true`); this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} delete dw ${this.workspaceName} -n ${this.namespace} || true`); + this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} delete dwt ${TestConstants.TS_SELENIUM_EDITOR}-${this.workspaceName} -n ${this.namespace} || true`); } applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString { @@ -89,6 +94,22 @@ 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}".`); + this.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} new-project ${projectName} -n ${this.namespace}`); + } + + 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}`); + } + + private isUserLoggedIn(): boolean { + const whoamiCommandOutput: ShellString = this.execWithLog('oc whoami && oc whoami --show-server=true'); + + return whoamiCommandOutput.stdout.includes(TestConstants.TS_SELENIUM_OCP_USERNAME) && whoamiCommandOutput.stdout.includes(this.getServerUrl()); + } + private getLoggingName(methodName: string): string { return `${this.constructor.name}.${methodName} - ${(this.KUBERNETES_COMMAND_LINE_TOOL)}`; } @@ -110,7 +131,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 {